{"id":36103,"date":"2005-03-23T07:04:00","date_gmt":"2005-03-23T07:04:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/03\/23\/why-does-the-debugger-show-me-the-wrong-virtual-function\/"},"modified":"2005-03-23T07:04:00","modified_gmt":"2005-03-23T07:04:00","slug":"why-does-the-debugger-show-me-the-wrong-virtual-function","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050323-00\/?p=36103","title":{"rendered":"Why does the debugger show me the wrong virtual function?"},"content":{"rendered":"<p>\nPointers to virtual functions all look basically the same\nand therefore,\n<a HREF=\"\/oldnewthing\/archive\/2005\/03\/22\/400373.aspx\">\nas we learned last time<\/a>,\nall end up merged\ninto a single function.\nHere&#8217;s a contrived example:\n<\/p>\n<pre>\nclass Class1\n{\npublic:\n virtual int f1() { return 0; }\n virtual int f2() { return 1; }\n};\nclass Class2\n{\npublic:\n virtual int g1() { return 2; }\n virtual int g2() { return 3; }\n};\nint (Class1::*pfn1)() = Class1::f2;\nint (Class2::*pfn2)() = Class2::g2;\n<\/pre>\n<p>\nIf you take a look at <code>pfn1<\/code> and <code>pfn2<\/code>\nyou&#8217;ll see that the point to the same function:\n<\/p>\n<pre>\n0:000&gt; dd pfn1 l1\n01002000  010010c8\n0:000&gt; dd pfn2 l1\n01002004  010010c8\n0:000&gt; u 10010c8 l2\n010010c8 8b01     mov     eax,[ecx]           ; first vtable\n010010ca ff6004   jmp     dword ptr [eax+0x4] ; second function\n<\/pre>\n<p>\nThat&#8217;s because the virtual functions <code>Class1::f2<\/code> and\n<code>Class2::g2<\/code> are both stored in the same location\nrelative to the respective object pointer:\nThey are the second entry in the first vtable.\nTherefore, the code to call those functions is identical\nand consequently has been merged by the linker.\n<\/p>\n<p>\nNotice that the function pointers are not direct pointers to\nthe concrete implementations of <code>Class1::f2<\/code> and\n<code>Class2::g2<\/code> because the function pointer might\nbe applied to a derived class which override the virtual\nfunction:\n<\/p>\n<pre>\nclass Class3 : public Class1\n{\npublic:\n virtual int f2() { return 9; }\n};\nClass3 c3;\n(c3.*pfn1)(); \/\/ calls Class3::f2\n<\/pre>\n<p>\nApplying the function pointer invokes the function on the derived class,\nwhich is the whole point of declaring the function <code>Class1::f2<\/code>\nas virtual in the first place.\n<\/p>\n<p>\nNote that the C++ language explicitly states that the result of comparing\nnon-null pointers to virtual member functions is &#8220;unspecified&#8221;,\nwhich is language-standards speak for &#8220;the result not only depends on\nthe implementation, but the implementation isn&#8217;t even required to\ndocument how it arrives at the result.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pointers to virtual functions all look basically the same and therefore, as we learned last time, all end up merged into a single function. Here&#8217;s a contrived example: class Class1 { public: virtual int f1() { return 0; } virtual int f2() { return 1; } }; class Class2 { public: virtual int g1() { [&hellip;]<\/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-36103","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Pointers to virtual functions all look basically the same and therefore, as we learned last time, all end up merged into a single function. Here&#8217;s a contrived example: class Class1 { public: virtual int f1() { return 0; } virtual int f2() { return 1; } }; class Class2 { public: virtual int g1() { [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36103","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=36103"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36103\/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=36103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=36103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=36103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}