A *aptr = new B();
delete aptr; // this line does not call B's destructor, only A's
// however...
B *bptr = new B();
delete bptr; // this line calls B's destructor then A's
I'm sure this is something simple, maybe even correct C++, but I'm not 100% on the C++ standard so any advice would be appreciated on how I can make the code call B's destructor. I'm using MSVC 5.
Thanks!
Starfall
Edited by - Starfall on 7/13/00 2:50:56 PM
C++ Destructor problem
Howdy
I'm running into a bit of trouble with C++ destructors. This is probably a fairly simple thing... but it's irritating me and I've never noticed the problem before. I have two classes, A and B. Each has a constructor and destructor defined. B is inherited from A. I have a pointer to A in my program which is assigned to point to an object of type B. This calls the constructor of B which calls the constructor of A, executes itself, and returns. However, when I destroy the object, because the pointer is of type A, only the destructor of A is run, and not the destructor of B. If I make the pointer of type B, it works fine. I have included a little code snippet so you can see what I am talking about (assume classes A and B are defined):
define A''s destructor as
virtual ~A();
i haven''t tried that with destructors, but i had the similar problem with a method inside my classes and i was told to define it as virtual in the base class, so i did and it worked perfectly. i think it''s the same thing for the destructor too
- Pouya / FOO!!!
#define PURE_STUPIDITY 128 PROGRAMMERS
virtual ~A();
i haven''t tried that with destructors, but i had the similar problem with a method inside my classes and i was told to define it as virtual in the base class, so i did and it worked perfectly. i think it''s the same thing for the destructor too
- Pouya / FOO!!!
#define PURE_STUPIDITY 128 PROGRAMMERS
Aha! So obvious I can''t believe I didn''t think of it! I was somehow under the impression that this should automatically occur for destructors. I use virtual all the time for other member functions, but it never occurred to me...
Thanks for the help.
Starfall
Thanks for the help.
Starfall
Are you using Visual C++?
I ask, because Visual C++ doesn''t insist on destructors being virtual, whereas I (and others) are certain that the C++ spec requires that a destructor be virtual, whether or not you declare it such.
I''m interested to know if other C++ compilers, such as GCC/DJGPP, Borland, etc, do this.
Anyway, the bottom line is, /always/ declare your destructors to be virtual - not just the base class. Why?
Well, imagine this:
Can you tell me what would happen? It''s undefined behaviour - I would expect that the CBaseWindow and CObject destructors would get called properly, but not the CButton one, because there''s no polymorphism chain explicitly declared.
This might not be what the C++ spec says, but since when do Microsoft and other obey a spec to the letter?
I think it''s despicable that Visual C++ doesn''t even generate a warning about non-virtual destructors, and that''s at ''warning level 4'' (for those that don''t know, that tells the compiler to be picky as hell).
Personally, I want my compiler to spew errors if it finds a non-virtual destructor, /or/ have an option to give a warning and then treat it as virtual anyway.
Can anyone give a good reason why it should be possible to break the polymorphism chain on destructors?
TheTwistedOne
http://www.angrycake.com
I ask, because Visual C++ doesn''t insist on destructors being virtual, whereas I (and others) are certain that the C++ spec requires that a destructor be virtual, whether or not you declare it such.
I''m interested to know if other C++ compilers, such as GCC/DJGPP, Borland, etc, do this.
Anyway, the bottom line is, /always/ declare your destructors to be virtual - not just the base class. Why?
Well, imagine this:
CObject{ virtual ~CObject();};CBaseWindow : public CObject{ ~CBaseWindow();};CButton : public CBaseWindow{ ~CButton();}CObject *pButton = new CButton();delete pButton;
Can you tell me what would happen? It''s undefined behaviour - I would expect that the CBaseWindow and CObject destructors would get called properly, but not the CButton one, because there''s no polymorphism chain explicitly declared.
This might not be what the C++ spec says, but since when do Microsoft and other obey a spec to the letter?
I think it''s despicable that Visual C++ doesn''t even generate a warning about non-virtual destructors, and that''s at ''warning level 4'' (for those that don''t know, that tells the compiler to be picky as hell).
Personally, I want my compiler to spew errors if it finds a non-virtual destructor, /or/ have an option to give a warning and then treat it as virtual anyway.
Can anyone give a good reason why it should be possible to break the polymorphism chain on destructors?
TheTwistedOne
http://www.angrycake.com
TheTwistedOnehttp://www.angrycake.com
Speed. Virtual gives you dynamic binding -> added overhead. You violate the principles of c++ if you demand that.
A polar bear is a rectangular bear after a coordinate transform.
Since you asked...
Besides speed, there are two other reasons not to make destructors virtual.
1) Size. Adding a single virtual method to a class requires the addition of a pointer to the vtable for each instance of the class. This is usually only 4 bytes, but it would double the size of a small class like this:
2) Adding a vtable pointer to a class makes it incompatable with the corresponding struct in C. If you need to pass struct data between libraries in C and C++, you have to make sure that there are no virtual methods (including destructors) on the structs.
However, I agree that the vast majority of time you DO want destructors to be virtual. It would be nice if VC flagged non-virtual destructors as errors, so long as there was a way to #pragma the error off for cases when you KNOW you want non-virtual destructors.
Besides speed, there are two other reasons not to make destructors virtual.
1) Size. Adding a single virtual method to a class requires the addition of a pointer to the vtable for each instance of the class. This is usually only 4 bytes, but it would double the size of a small class like this:
class point { unsigned short x, y;};
2) Adding a vtable pointer to a class makes it incompatable with the corresponding struct in C. If you need to pass struct data between libraries in C and C++, you have to make sure that there are no virtual methods (including destructors) on the structs.
However, I agree that the vast majority of time you DO want destructors to be virtual. It would be nice if VC flagged non-virtual destructors as errors, so long as there was a way to #pragma the error off for cases when you KNOW you want non-virtual destructors.
Borland and Metrowerks compilers do not require virtual dtors
Such a requirement, as said before is, in fact, a violation of the C++ spec.
A dtor is virtual if declared as such or, if it inherits from a base class which has a destructor declared as virtual ( just like methods )
If you do not explicitly declare a dtor the compiler generates one for you - if your class inherits from a class with a virtual dtor then the compiler will generate a virtual dtor, otherwise it will create a non-virtual one.
Personally, I like to make sure and declare things virtual in every class in the heirarchy that they need to be. It makes things clearer when looking at one module. For example:
Module A -
class Base
{
public:
Base();
virtual ~Base();
virtual void Nothing() = 0;
};
Module B - ( a separate .cpp file )
- include Module A -
class Derived : public Base
{
private:
long iVal;
public:
Derived();
virtual ~Derived();
virtual void Nothing();
};
However, declaring all methods virtual can be overkill. Especially since virtual causes inline functions to be out-of-line when the compiler cannot determine the type at compilation time.
Edited by - SteveC on July 14, 2000 5:53:51 PM
Edited by - SteveC on July 14, 2000 5:55:13 PM
Such a requirement, as said before is, in fact, a violation of the C++ spec.
A dtor is virtual if declared as such or, if it inherits from a base class which has a destructor declared as virtual ( just like methods )
If you do not explicitly declare a dtor the compiler generates one for you - if your class inherits from a class with a virtual dtor then the compiler will generate a virtual dtor, otherwise it will create a non-virtual one.
Personally, I like to make sure and declare things virtual in every class in the heirarchy that they need to be. It makes things clearer when looking at one module. For example:
Module A -
class Base
{
public:
Base();
virtual ~Base();
virtual void Nothing() = 0;
};
Module B - ( a separate .cpp file )
- include Module A -
class Derived : public Base
{
private:
long iVal;
public:
Derived();
virtual ~Derived();
virtual void Nothing();
};
However, declaring all methods virtual can be overkill. Especially since virtual causes inline functions to be out-of-line when the compiler cannot determine the type at compilation time.
Edited by - SteveC on July 14, 2000 5:53:51 PM
Edited by - SteveC on July 14, 2000 5:55:13 PM
Armitage: Speed. Hmm. Personally, I''d take predictability over performance in the case of destructors.
Syzygy: Oh. I tend to forget that a struct is a class according to C++. That''s a good reason.
SteveC: I quite agree. Regardless of what a compiler does or doesn''t do, it''s always best to write things out fully, for everybody''s sake.
I''m aware of default constructors and destructors - which is why you''d find a lot of empty ones in my classes, if you were to peek at them.
I''m not talking about functions in general, though. I fully understand that making everything virtual is a road to performance hell.
Overall, I suppose that it''s unfair to demand that the default be that destructors are virtual. The biggest argument against, I think, would be that such is the opposite of the normal behaviour.
I don''t think I''m being unreasonable in desiring compilers to tell you if you forget to make a destructor virtual, though. Even as a turned-off-by-default option.
Are you listening, Bill
TheTwistedOne
http://www.angrycake.com
Syzygy: Oh. I tend to forget that a struct is a class according to C++. That''s a good reason.
SteveC: I quite agree. Regardless of what a compiler does or doesn''t do, it''s always best to write things out fully, for everybody''s sake.
I''m aware of default constructors and destructors - which is why you''d find a lot of empty ones in my classes, if you were to peek at them.
I''m not talking about functions in general, though. I fully understand that making everything virtual is a road to performance hell.
Overall, I suppose that it''s unfair to demand that the default be that destructors are virtual. The biggest argument against, I think, would be that such is the opposite of the normal behaviour.
I don''t think I''m being unreasonable in desiring compilers to tell you if you forget to make a destructor virtual, though. Even as a turned-off-by-default option.
Are you listening, Bill
TheTwistedOne
http://www.angrycake.com
TheTwistedOnehttp://www.angrycake.com
Well, I misread the question somewhat. I didn't realize that he meant "breaking" a virtual chain. I thought he wanted a reason for omitting a virtual dtor from the beginning (gave my reply in regard to the first post). If you're building a concrete class you shouldn't use virtual, imo, and I honestly don't know what happens if you start making them virtual further down the tree?
But if there is a virtual one at the top, I'd like to find out from the compiler before introducing small...features into my programs
Edited by - Armitage on July 15, 2000 6:07:38 AM
Edited by - Armitage on July 15, 2000 6:09:25 AM
But if there is a virtual one at the top, I'd like to find out from the compiler before introducing small...features into my programs
Edited by - Armitage on July 15, 2000 6:07:38 AM
Edited by - Armitage on July 15, 2000 6:09:25 AM
A polar bear is a rectangular bear after a coordinate transform.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement