{"id":40713,"date":"2004-02-09T07:00:00","date_gmt":"2004-02-09T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/02\/09\/pointers-to-member-functions-are-very-strange-animals\/"},"modified":"2004-02-09T07:00:00","modified_gmt":"2004-02-09T07:00:00","slug":"pointers-to-member-functions-are-very-strange-animals","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040209-00\/?p=40713","title":{"rendered":"Pointers to member functions are very strange animals"},"content":{"rendered":"<p>\nPointers to member functions are very strange animals.<\/p>\n<p>\n<b>Warning<\/b>: The discussion that follows is specific to\nthe way pointers to member functions are implemented by the\nMicrosoft Visual C++ compiler.  Other compilers may do things\ndifferently.\n<\/p>\n<p>\nWell, okay, if you only use single inheritance, then\npointers to member functions are just a pointer to the\nstart of the function, since all the base classes\nshare the same &#8220;this&#8221; pointer:\n<\/p>\n<pre>\nclass Simple { int s; void SimpleMethod(); };\nclass Simple2 : public Simple\n  { int s2; void Simple2Method(); };\nclass Simple3 : public Simple2\n  { int s3; Simple3Method(); };\n<\/pre>\n<table BORDER=\"0\">\n<col SPAN=\"3\" ALIGN=\"center\">\n<tr>\n<td valign=\"top\">p<\/td>\n<td valign=\"top\">&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;width: 10em\">\n<div STYLE=\"border: solid 1px buttonshadow;margin: .5ex\">\n<div STYLE=\"border: solid 1px buttonshadow;margin: .5ex\">\n       Simple::s\n     <\/div>\n<p>       Simple2::s2\n   <\/p><\/div>\n<p>    Simple3::s3\n<\/td>\n<\/tr>\n<\/table>\n<p>\nSince they all use the same &#8220;this&#8221; pointer (p), a pointer to\na member function of Base can be used as if it were a pointer\nto a member function of Derived2 without any adjustment\nnecessary.\n<\/p>\n<blockquote CLASS=\"m\"><p>\nThe size of a pointer-to-member-function of a class that\nuses only single inheritance is just the size of a pointer.\n<\/p><\/blockquote>\n<p>\nBut if you have multiple base classes, then things get interesting.<\/p>\n<pre>\nclass Base1 { int b1; void Base1Method(); };\nclass Base2 { int b2; void Base2Method(); };\nclass Derived : public Base1, Base2\n  { int d; void DerivedMethod(); };\n<\/pre>\n<table BORDER=\"0\" CELLSPACING=\"0\">\n<col SPAN=\"3\" ALIGN=\"center\">\n<tr>\n<td valign=\"top\">p<\/td>\n<td valign=\"top\">&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;border-bottom: none;width: 10em\">\n<div STYLE=\"border: solid 1px buttonshadow;margin: .5ex\">\n       Base1::b1\n     <\/div>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">q<\/td>\n<td valign=\"top\">&rarr;<\/td>\n<td STYLE=\"border: solid 1px buttonshadow;border-top: none;width: 10em\">\n<div STYLE=\"border: solid 1px buttonshadow;margin: .5ex\">\n       Base2::b2\n     <\/div>\n<p>       Derived::d\n    <\/td>\n<\/tr>\n<\/table>\n<p>\nThere are now two possible &#8220;this&#8221; pointers.  The first (p) is used\nby both Derived and Base1, but the second (q) is used by Base2.\n<\/p>\n<p>\nA pointer to a member function of Base1 can be used as a pointer\nto a member function of Derived, since they both use the same &#8220;this&#8221;\npointer.  But a pointer to a member function of Base2 cannot be\nused as-is as a pointer to a member function of Derived, since the\n&#8220;this&#8221; pointer needs to be adjusted.\n<\/p>\n<p>\nThere are many ways of solving this.\nHere&#8217;s how the Visual Studio compiler decides to handle it:\n<\/p>\n<p>\nA pointer to a member function of a multiply-inherited class\nis really a structure.\n<\/p>\n<table BORDER=\"0\">\n<col ALIGN=\"center\">\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;width: 10em\">\n    Address of function\n    <\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px buttonshadow;width: 10em\">\n       Adjustor\n    <\/td>\n<\/tr>\n<\/table>\n<blockquote CLASS=\"m\"><p>\nThe size of a pointer-to-member-function of a class that\nuses multiple inheritance is the size of a pointer plus the\nsize of a size_t.\n<\/p><\/blockquote>\n<p>\nCompare this to the case of a class that uses only single inheritance.\n<\/p>\n<blockquote CLASS=\"m\"><p>\nThe size of a pointer-to-member-function can change depending on\nthe class!\n<\/p><\/blockquote>\n<p>\nAside: Sadly, this means that Rich Hickey&#8217;s wonderful technique of\n<a HREF=\"http:\/\/www.tutok.sk\/fastgl\/callback.html\">Callbacks\nin C++ Using Template Functors<\/a> cannot be used as-is.\nYou have to fix the place where he writes the comment<\/p>\n<pre>\n\/\/ Note: this code depends on all ptr-to-mem-funcs being same size\n<\/pre>\n<\/p>\n<p>\nOkay, back to our story.\n<\/p>\n<p>To call through a pointer to a member function, the &#8220;this&#8221;\npointer is adjusted by the Adjustor, and then the function\nprovided is called.  A call through\na function pointer might be compiled like this:\n<\/p>\n<pre>\nvoid (Derived::*pfn)();\nDerived d;\n(d.*pfn)();\n  lea  ecx, d       ; ecx = \"this\"\n  add  ecx, pfn[4]  ; add adjustor\n  call pfn[0]       ; call\n<\/pre>\n<p>\nWhen would an adjustor be nonzero?  Consider the case above.\nThe function Derived::Base2Method() is really Base2::Base2Method()\nand therefore expects to receive &#8220;q&#8221; as its &#8220;this&#8221; pointer.\nIn order to convert a &#8220;p&#8221; to a &#8220;q&#8221;, the adjustor must have the\nvalue sizeof(Base1), so that when the first line of Base2::Base2Method()\nexecutes, it receives the expected &#8220;q&#8221; as its &#8220;this&#8221; pointer.\n<\/p>\n<p>\n&#8220;But why not just use a thunk instead of manually adding the adjustor?&#8221;\nIn other words, why not just use a simple pointer to a thunk that\ngoes like this:\n<\/p>\n<pre>\nDerived::Base2Method thunk:\n    add ecx, sizeof(Base1)  ; convert \"p\" to \"q\"\n    jmp Base2::Base2Method  ; continue\n<\/pre>\n<p>\nand use that thunk as the function pointer?\n<\/p>\n<p>\nThe reason: Function pointer casts.\n<\/p>\n<p>\nConsider the following code:<\/p>\n<pre>\nvoid (Base2::*pfnBase2)();\nvoid (Derived::*pfnDerived)();\npfnDerived = pfnBase2;\n  mov  ecx, pfnBase2            ; ecx = address\n  mov  pfnDerived[0], ecx\n  mov  pfnDerived[4], sizeof(Base1) ; adjustor!\n<\/pre>\n<p>\nWe start with a pointer to a member function of Base2,\nwhich is a class that uses only single inheritance, so it\nconsists of just a pointer to the code.\nTo assign it to a pointer to a member function\nof Derived, which uses multiple inheritance, we can re-use\nthe function address, but we now need an adjustor so that\nthe pointer &#8220;p&#8221; can properly be converted to a &#8220;q&#8221;.\n<\/p>\n<p>\nNotice that the code doesn&#8217;t know what function pfnBase2\npoints to, so it can&#8217;t just replace it with the matching thunk.\nIt would have to generate a thunk at runtime and somehow\nuse its psychic powers to decide when the memory can safely\nbe freed.  (This is C++.  No garbage collector here.)\n<\/p>\n<p>\nNotice also that when pfnBase2\ngot cast to a pointer to member function of Derived, its size changed,\nsince it went from a pointer to a function in a class that uses only single\ninheritance to a pointer to a function in a class\nthat uses multiple inheritance.\n<\/p>\n<blockquote CLASS=\"m\"><p>\nCasting a function pointer can change its size!\n<\/p><\/blockquote>\n<p>\nI bet that you didn&#8217;t know that before reading this entry.\n<\/p>\n<p>\nThere&#8217;s still an awful lot more to this topic,\nbut I&#8217;m going to stop here before everybody&#8217;s head explodes.\n<\/p>\n<p>\n<b>Exercise<\/b>:\nConsider the class<\/p>\n<pre>\nclass Base3 { int b3; void Base3Method(); };\nclass Derived2 : public Base3, public Derived { };\n<\/pre>\n<p>How would the following code be compiled?<\/p>\n<pre>\nvoid (Derived::*pfnDerived)();\nvoid (Derived2::*pfnDerived2();\npfnDerived2 = pfnDerived;\n<\/pre>\n<p>\nAnswer to appear tomorrow.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pointers to member functions are very strange animals. Warning: The discussion that follows is specific to the way pointers to member functions are implemented by the Microsoft Visual C++ compiler. Other compilers may do things differently. Well, okay, if you only use single inheritance, then pointers to member functions are just a pointer to the [&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-40713","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Pointers to member functions are very strange animals. Warning: The discussion that follows is specific to the way pointers to member functions are implemented by the Microsoft Visual C++ compiler. Other compilers may do things differently. Well, okay, if you only use single inheritance, then pointers to member functions are just a pointer to the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40713","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=40713"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40713\/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=40713"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40713"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40713"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}