{"id":32583,"date":"2006-01-20T07:00:00","date_gmt":"2006-01-20T15:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/01\/20\/the-vtable-does-not-always-go-at-the-start-of-the-object\/"},"modified":"2006-01-20T07:00:00","modified_gmt":"2006-01-20T15:00:00","slug":"the-vtable-does-not-always-go-at-the-start-of-the-object","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060120-00\/?p=32583","title":{"rendered":"The vtable does not always go at the start of the object"},"content":{"rendered":"<p><!--\nv\\:* { behavior: url(#default#VML); }\nv\\:shape.v_arrow { position: relative; height: 1em; width: 5em }\n--><\/p>\n<p>\nAlthough the diagrams I presented in my discussion of\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/05\/68017.aspx\">\nThe layout of a COM object<\/a>\nplace the vtable at the beginning of the underlying C++ object,\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/03\/23\/400938.aspx#401122\">\nthere is no actual requirement that it be located there<\/a>.\nIt is perfectly legal for the vtable to be in the middle or even\nat the end of the object, as long as the functions in the vtable\nknow how to convert the address of the vtable pointer to the\naddress of the underlying object.\nIndeed, in the second diagram in that article, you can see that\nthe &#8220;q&#8221; pointer indeed points into the middle of the object.\n<\/p>\n<p>\nHere&#8217;s an example that puts the vtable at the end of the object:\n<\/p>\n<pre>\nclass Data {\npublic:\n Data() : m_cRef(1) { }\n virtual ~Data() { }\n LONG m_cRef;\n};\nclass VtableAtEnd : Data, public IUnknown {\npublic:\n STDMETHODIMP QueryInterface(REFIID riid, void **ppvOut)\n {\n  if (riid == IID_IUnknown) {\n   AddRef();\n   *ppvOut = static_cast&lt;IUnknown*&gt;(this);\n   return S_OK;\n  }\n  *ppvOut = NULL;\n   return E_NOINTERFACE;\n }\n STDMETHODIMP_(ULONG) AddRef()\n {\n  return InterlockedIncrement(&amp;m_cRef);\n }\n STDMETHODIMP_(ULONG) Release()\n {\n  LONG cRef = InterlockedDecrement(&amp;m_cRef);\n  if (!cRef) delete this;\n  return cRef;\n }\n};\n<\/pre>\n<p>\nThe layout of this object may very well be as follows:\n(Warning: Diagram requires a VML-enabled browser.)\n<\/p>\n<table BORDER=\"0\">\n<col SPAN=\"5\" ALIGN=\"center\">\n<tr>\n<td><\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px buttonshadow\">&nbsp; &nbsp;Data.vtbl&nbsp; &nbsp;<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px buttonshadow\">&nbsp; &nbsp;m_cRef&nbsp; &nbsp;<\/td>\n<\/tr>\n<tr>\n<td>p<\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px buttonshadow\">&nbsp; &nbsp;IUnknown.vtbl&nbsp; &nbsp;<\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">QueryInterface<\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"3\" COLSPAN=\"4\"><\/td>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">AddRef<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;height: 2em\">Release<\/td>\n<\/tr>\n<\/table>\n<p>\nObserve that in this particular object layout, the vtable\nresides at the end of the object rather than at the beginning.\nThis is perfectly legitimate behavior.\nAlthough it is the most common object layout to put the vtable\nat the beginning, COM imposes no requirement that it be done\nthat way.\nIf you want to put your vtable at the end and use negative\noffsets to access your object&#8217;s members, then more power to you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There is no requirement that it does, and it often doesn&#8217;t.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-32583","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There is no requirement that it does, and it often doesn&#8217;t.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/32583","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=32583"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/32583\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=32583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=32583"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=32583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}