{"id":2953,"date":"2013-10-11T07:00:00","date_gmt":"2013-10-11T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/10\/11\/c-corner-case-you-can-implement-pure-virtual-functions-in-the-base-class\/"},"modified":"2013-10-11T07:00:00","modified_gmt":"2013-10-11T07:00:00","slug":"c-corner-case-you-can-implement-pure-virtual-functions-in-the-base-class","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20131011-00\/?p=2953","title":{"rendered":"C++ corner case: You can implement pure virtual functions in the base class"},"content":{"rendered":"<p>\nIn our\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/04\/28\/122037.aspx\">\ndiscussion <code>__purecall<\/code><\/a>,\nwe saw that you can declare a pure virtual function with the\n<code>= 0<\/code> syntax,\nand if you try to call one of these functions from the base class,\nyou will get the dreaded <i>R6025 &#8211; pure virtual function call<\/i>\nerror.\n<\/p>\n<p>\nIn that article, I wrote that a pure virtual function is\n&#8220;a method which is declared by the base class, but for which\nno implementation is provided.&#8221;\nThat statement is false.\n<\/p>\n<p>\nYou can provide an implementation for a pure virtual method in C++.\n<\/p>\n<p>\n&#8220;That&#8217;s crazy talk,&#8221; I hear you say.\n<\/p>\n<p>\nOkay, let&#8217;s start talking crazy:\n<\/p>\n<pre>\n#include &lt;iostream&gt;\nclass Base {\npublic:\n Base() { f(); }\n virtual void f() = 0;\n};\nclass Derived : public Base {\npublic:\n Derived() { f(); }\n virtual void f() { std::cout &lt;&lt; \"D\"; }\n};\nint main(int, char **)\n{\n Derived d;\n return 0;\n}\n<\/pre>\n<p>\nWhat happens when the <code>test<\/code>\nfunction constructs a <code>Derived<\/code>?\n<\/p>\n<p>\nTrick question,\nbecause you get a linker error\nwhen you try to build the project.\n<\/p>\n<p>\nThere are many questions lurking here,\nlike &#8220;Why do I get a linker error?&#8221;\nand &#8220;Why isn&#8217;t it a compiler error?&#8221;\nWe&#8217;ll get back to those questions later.\nFor now, let&#8217;s get the code to build.\n<\/p>\n<pre>\nclass Base {\npublic:\n Base() { <font COLOR=\"blue\">call_f()<\/font>; }\n virtual void f() = 0;\n <font COLOR=\"blue\">void call_f() { f(); }<\/font>\n};\n<\/pre>\n<p>\nOkay, with this change (hiding the call to <code>f<\/code>\ninside a function called <code>call_f<\/code>),\nthe code compiles,\nso now we can answer the question:\n<\/p>\n<p>\n<b>Answer<\/b>: You get the dreaded purecall error,\nbecause the base class constructor\nhas engaged in a conspiracy with the function <code>call_f<\/code>\nto call the function <code>f<\/code> from its constructor.\nSince <code>f<\/code> is a pure virtual function,\nyou get the purecall error.\n<\/p>\n<p>\nOkay, next question:\nWhy didn&#8217;t the original code result in a compiler error?\n<\/p>\n<p>\n<b>Answer<\/b>:\nThe compiler is not required to do a full code flow analysis\nto determine whether you are calling a pure virtual method\nfrom a constructor.\nThe language forbids it, but no diagnostic is required\nand the behavior is undefined.\n<\/p>\n<blockquote CLASS=\"q\"><p>\nMember functions can be called from a constructor (or destructor)\nof an abstract class;\nthe effect of making a virtual call (10.3) to a pure virtual\nfunction directly or indirectly for the object being created\n(or destroyed) from such a constructor (or destructor) is undefined.\n<\/p><\/blockquote>\n<p>\nBut why did it result in a linker error?\n<\/p>\n<p>\n<b>Answer<\/b>:\nAs we learned during the discussion of <code>__purecall<\/code>,\nC++ objects change identity during their construction,\nand at the point that the <code>Base<\/code> constructor is running,\nthe object is still a <code>Base<\/code>,\nso the <i>final overrider<\/i> method is <code>Base::f<\/code>\nTherefore, when you called\n<code>f()<\/code> from the <code>Base<\/code> constructor,\nyou were actually calling <code>Base::f<\/code>.\n<\/p>\n<p>\nAnd you never defined <code>Base::f<\/code>,\nso the linker complained.\n<\/p>\n<p>\n&#8220;Wait, I can define <code>Base::f<\/code>?&#8221;\n<\/p>\n<p>\nSure, let&#8217;s do it.\n<i>At the end of the program<\/i> (even after the definition\nof <code>main<\/code>)\nadd this code:\n<\/p>\n<pre>\nvoid Base::f()\n{\n std::cout &lt;&lt; \"B\";\n}\n<\/pre>\n<p>\nNow the program compiles,\nand when you run it, well, we saw that the standard leaves this\nundefined, so you might crash, or monkeys might fly out of your nose,\nor the runtime library may go back in time and kill your parents.\n(We&#8217;ll see in a future article\nhow undefined behavior can lead to time travel.\nHow&#8217;s that for a teaser!)\n<\/p>\n<p>\nBut one implementation might generate this program output:\n<\/p>\n<pre>\nBD\n<\/pre>\n<p>\nThis particular implementation decided not to try very hard to detect the\ncase where you are calling <code>Base::f<\/code> during the\nconstructor and just lets the call happen,\nand it ends up calling the method you defined later.\n<\/p>\n<p>\n&#8220;But if I&#8217;m not allowed to call the pure virtual function from\na constructor or destructor,\nand if I call the method\nafter construction, it always calls the version of the function\nthat the derived class overrode,\nthen how could this code ever execute at all (legitimiately)?\nIn other words,\nwhat conforming program could ever print the letter <code>B<\/code>?&#8221;\n<\/p>\n<p>\nThe function cannot be called implicitly, but it can be called explicitly:\n<\/p>\n<pre>\nclass Base {\npublic:\n Base() { <font COLOR=\"red\">\/* f(); *\/<\/font> }\n virtual void f() = 0;\n};\nvoid Base::f()\n{\n std::cout &lt;&lt; \"B\";\n}\nclass Derived : public Base {\npublic:\n Derived() { f(); }\n virtual void f() { std::cout &lt;&lt; \"D\"; <font COLOR=\"blue\">Base::f();<\/font> }\n};\nint main(int, char **)\n{\n Derived d;\n return 0;\n}\n<\/pre>\n<p>\nFirst, we got rid of the illegal call to <code>f()<\/code>\nin the base class constructor (to keep our code legit).\nNext, we adjusted our override version of <code>f<\/code>\nso that it calls the base class method after doing some\ncustom work.\n<\/p>\n<p>\nThis time, the program prints <code>DB<\/code>,\nand the code is perfectly legitimate this time.\nNo undefined behavior, nothing up my sleeve.\n<\/p>\n<p>\nWhat happened here?\n<\/p>\n<p>\nThe derived class constructor called the <code>f<\/code>\nmethod, which maps to\n<code>Derived::f<\/code>.\nThat function prints the letter D,\nand then it calls the base class version\n<code>Base::f<\/code> explicitly.\nThe base class version then prints the letter B.\n<\/p>\n<p>\nThis is actually nothing new; this is how overridden\nmethods work in general.\nThe only wrinkle here is that the base class method\ncan be called only via explicit qualification;\nthere is no way to call it implicitly.\n<\/p>\n<p>\nThis was a rather long-winded way of calling out a weird\ncorner case in C++ that most people don&#8217;t even realize exists:\nA pure virtual function can have an implementation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In our discussion __purecall, we saw that you can declare a pure virtual function with the = 0 syntax, and if you try to call one of these functions from the base class, you will get the dreaded R6025 &#8211; pure virtual function call error. In that article, I wrote that a pure virtual function [&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-2953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>In our discussion __purecall, we saw that you can declare a pure virtual function with the = 0 syntax, and if you try to call one of these functions from the base class, you will get the dreaded R6025 &#8211; pure virtual function call error. In that article, I wrote that a pure virtual function [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2953","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=2953"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2953\/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=2953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=2953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=2953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}