{"id":39443,"date":"2004-05-07T07:01:00","date_gmt":"2004-05-07T07:01:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/05\/07\/when-should-your-destructor-be-virtual\/"},"modified":"2004-05-07T07:01:00","modified_gmt":"2004-05-07T07:01:00","slug":"when-should-your-destructor-be-virtual","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040507-00\/?p=39443","title":{"rendered":"When should your destructor be virtual?"},"content":{"rendered":"<p>When should your C++ object&#8217;s destructor be virtual? <\/p>\n<p>First of all, what does it mean to have a virtual destructor? <\/p>\n<p>Well, what does it mean to have a virtual method? <\/p>\n<p>If a method is virtual, then calling the method on an object always invokes the method as implemented by the most heavily derived class. If the method is not virtual, then the implementation corresponding to the compile-time type of the object pointer. <\/p>\n<p>For example, consider this: <\/p>\n<pre>class Sample {\npublic:\n void f();\n virtual void vf();\n};\nclass Derived : public Sample {\npublic:\n void f();\n void vf();\n}\nvoid function()\n{\n Derived d;\n Sample* p = &amp;d;\n p-&gt;f();\n p-&gt;vf();\n}\n<\/pre>\n<p>The call to <code>p-&gt;f()<\/code> will result in a call to <code>Sample::f<\/code> because <code>p<\/code> is a pointer to a <code>Sample<\/code>. The actual object is of type <code>Derived<\/code>, but the pointer is merely a pointer to a <code>Sample<\/code>. The pointer type is used because <code>f<\/code> is not virtual. <\/p>\n<p>On the other hand, the call to The call to <code>p-&gt;vf()<\/code> will result in a call to <code>Derived::vf<\/code>, the most heavily derived type, because <code>vf<\/code> is virtual. <\/p>\n<p>Okay, you knew that. <\/p>\n<p>Virtual destructors work exactly the same way. It&#8217;s just that you rarely invoke the destructor explicitly. Rather, it&#8217;s invoked when an automatic object goes out of scope or when you <code>delete<\/code> the object. <\/p>\n<pre>void function()\n{\n Sample* p = new Derived;\n delete p;\n}\n<\/pre>\n<p>Since <code>Sample<\/code> does not have a virtual destructor, the <code>delete p<\/code> invokes the destructor of the class of the pointer (<code>Sample::~Sample()<\/code>), rather than the destructor of the most derived type (<code>Derived::~Derived()<\/code>). And as you can see, this is the wrong thing to do in the above scenario. <\/p>\n<p>Armed with this information, you can now answer the question. <\/p>\n<p>A class must have a virtual destructor if it meets both of the following criteria: <\/p>\n<ul>\n<li>You do a <code>delete p<\/code>.\n<li>It is possible that <code>p<\/code> actually points to a derived class. <\/li>\n<\/ul>\n<p>Some people say that you need a virtual destructor if and only if you have a virtual method. This is wrong in both directions. <\/p>\n<p>Example of a case where a class has no virtual methods but still needs a virtual destructor: <\/p>\n<pre>class Sample { };\nclass Derived : public Sample\n{\n CComPtr&lt;IStream&gt; m_p;\npublic:\n Derived() { CreateStreamOnHGlobal(NULL, TRUE, &amp;m_p); }\n};\nSample *p = new Derived;\ndelete p;\n<\/pre>\n<p>The <code>delete p<\/code> will invoke <code>Sample::~Sample<\/code> instead of <code>Derived::~Derived<\/code>, resulting in a leak of the stream <code>m_p<\/code>. <\/p>\n<p>And here&#8217;s an example of a case where a class has virtual methods but does not require a virtual destructor. <\/p>\n<pre>class Sample { public: virtual void vf(); }\nclass Derived : public Sample { public: virtual void vf(); }\nDerived *p = new Derived;\ndelete p;\n<\/pre>\n<p>Since the object deletion occurs from the pointer type that matches the type of the actual object, the correct destructor will be invoked. This pattern happens often in COM objects, which expose several virtual methods corresponding to its interfaces, but where the object itself is destroyed by its own implementation and not from a base calss pointer. (Notice that no COM interfaces contain virtual destructors.) <\/p>\n<p>The problem with knowing when to make your destructor virtual or not is that you have to know how people will be using your class. If C++ had a &#8220;sealed&#8221; keyword, then the rule would be simpler: If you do a &#8220;<code>delete p<\/code>&#8221; where <code>p<\/code> is a pointer to an unsealed class, then that class needs have a virtual destructor. (The imaginary &#8220;sealed&#8221; keyword makes it explicit when a class can act as the base class for another class.) <\/p>\n","protected":false},"excerpt":{"rendered":"<p>When should your C++ object&#8217;s destructor be virtual? First of all, what does it mean to have a virtual destructor? Well, what does it mean to have a virtual method? If a method is virtual, then calling the method on an object always invokes the method as implemented by the most heavily derived class. If [&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-39443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>When should your C++ object&#8217;s destructor be virtual? First of all, what does it mean to have a virtual destructor? Well, what does it mean to have a virtual method? If a method is virtual, then calling the method on an object always invokes the method as implemented by the most heavily derived class. If [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/39443","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=39443"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/39443\/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=39443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=39443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=39443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}