{"id":444,"date":"2019-05-11T10:38:44","date_gmt":"2019-05-11T17:38:44","guid":{"rendered":"http:\/\/35.243.195.209\/?p=444"},"modified":"2020-04-11T22:48:23","modified_gmt":"2020-04-12T05:48:23","slug":"virtual-functions-constructors-and-destructors","status":"publish","type":"post","link":"https:\/\/nanzhou.cc\/index.php\/2019\/05\/11\/virtual-functions-constructors-and-destructors\/","title":{"rendered":"Virtual Functions, Constructors, and Destructors"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>In this post, I will introduce rules related to constructors and destructors of classes which has virtual functions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusions<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">Golden Rule 1: Define a virtual destructor immediately<\/h4>\n\n\n\n<h4 class=\"wp-block-heading\">Golden Rule 2: Do not invoke virtual functions from constructors or destructors<\/h4>\n\n\n\n<h2 class=\"wp-block-heading\">Details<\/h2>\n\n\n\n<p>In C++, Virtual functions allow for the choice of member function calls to be determined at run time based on the dynamic type of the object that the member function is being called on, which supports OOP practices commonly associated with object inheritance and function overriding.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Golden Rule 1<\/h4>\n\n\n\n<p>Firstly you should notice that in <a href=\"https:\/\/wiki.sei.cmu.edu\/confluence\/display\/cplusplus\/AA.+Bibliography#AA.Bibliography-ISO\/IEC14882-2014\">C++ Standard<\/a>,<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">If a class has no user-declared destructor, a destructor\nis implicitly declared as defaulted. An implicitly declared\ndestructor is an inline public member of its class.<\/code><\/pre>\n\n\n\n<p>In many design patterns, people will implement classes which are inherited from a virtual interface. Customers might use pointers of the interface which point to the derived instance. It comes to the problem.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">class Base \n{\n    \/\/ an interface consists of some virtual methods\n};\n\nclass Derived : public Base\n{\n    ~Derived()\n    {\n        \/\/ Do some important cleanup\n    }\n};<\/code><\/pre>\n\n\n\n<p>When customers want to delete an instance of a derived class through a pointer to base class, if base&#8217;s destructor is not virtual, <code>delete b<\/code> has undefined behavior. In most implementations, the call to the destructor will be resolved like any non-virtual code, meaning that the destructor of the base class will be called but not the one of the derived class, resulting in a resources leak.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Golden Rule 2<\/h4>\n\n\n\n<p>Calling virtual functions from a constructor or destructor is dangerous and should be avoided whenever possible. All C++ implementations should call the version of the function defined at the level of the hierarchy in the current constructor and no further.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\"> class B {\n    public:\n        B(const string&amp; ss) { cout &lt;&lt; \"B constructor\\n\"; f(ss); }\n        virtual void f(const string&amp;) { cout &lt;&lt; \"B::f\\n\";}\n    };\n    class D : public B {\n    public:\n        D(const string &amp; ss) :B(ss) { cout &lt;&lt; \"D constructor\\n\";}\n        void f(const string&amp; ss) { cout &lt;&lt; \"D::f\\n\"; s = ss; }\n    private:\n        string s;\n    };\n    int main()\n    {\n        D d(\"Hello\");\n    }<\/code><\/pre>\n\n\n\n<p>D attempts to overrides B&#8217;s f. And the programmer knows that the order of construction is from base to derived. He then naively thinks once f is overridden, B&#8217;s constructor will actually call D&#8217;s f. Which is great.<br>However, the result is<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"\" class=\"\">B constructor\nB::f\nD constructor<\/code><\/pre>\n\n\n\n<p>Then you may ask when my base class\u2019s constructor calls a virtual function on its this object, why doesn\u2019t my derived class\u2019s override of that virtual function gets invoked. Because it is <strong>dangerous<\/strong>.<\/p>\n\n\n\n<p>Consider what would happen if the rule were different so that D::f() was called from B::B(): Because the constructor D::D() hadn\u2019t yet been run, D::f() would try to assign its argument to an uninitialized string s. The result would most likely be an immediate crash.<\/p>\n\n\n\n<p><a href=\"https:\/\/isocpp.org\/wiki\/faq\/strange-inheritance#calling-virtuals-from-ctors\">Luckily C++ is protecting you from this danger<\/a>.<br>In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn\u2019t yet happened. Objects are constructed from the base up, \u201cbase before derived\u201d. So is the destructor.<\/p>\n\n\n\n<p>The correct way is every class do its own things.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">class B {\n  void seize_mine();\n  void release_mine();\n\npublic:\n  B() { seize_mine(); }\n  virtual ~B() { release_mine(); }\n\nprotected:\n  virtual void seize() { seize_mine(); }\n  virtual void release() { release_mine(); }\n};\n\nclass D : public B {\n  void seize_mine();\n  void release_mine();\n\npublic:\n  D() { seize_mine(); }\n  virtual ~D() { release_mine(); }\n\nprotected:\n  void seize() override {\n    B::seize();\n    seize_mine();\n  }\n\n  void release() override {\n    release_mine();\n    B::release();\n  }\n};<\/code><\/pre>\n\n\n\n<p><code>seize_mine<\/code> and <code>release_mine<\/code> are overrided and each class has its own copy in each level.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Reference<\/h2>\n\n\n\n<p><a href=\"https:\/\/wiki.sei.cmu.edu\/confluence\/display\/cplusplus\/OOP52-CPP.+Do+not+delete+a+polymorphic+object+without+a+virtual+destructor\">SEI CERT C++ Coding Standard<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary In this post, I will introduce rules related to constructors and destructors of classes which has virtual functions. Conclusions Golden Rule 1: Define a virtual destructor immediately Golden Rule 2: Do not invoke virtual functions from constructors or destructors Details In C++, Virtual functions allow for the choice of member function calls to be&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,59,5,25],"tags":[],"class_list":["post-444","post","type-post","status-publish","format-standard","hentry","category-c","category-ood","category-proglang","category-software-engineering"],"_links":{"self":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/444","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/comments?post=444"}],"version-history":[{"count":3,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/444\/revisions"}],"predecessor-version":[{"id":959,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/444\/revisions\/959"}],"wp:attachment":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/media?parent=444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/categories?post=444"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/tags?post=444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}