472,982 Members | 2,185 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,982 software developers and data experts.

Virtual Destructor

Please answer my questions below - thanks!

1. Why "Derived constructor" is called but "Derived destructor" not in Case
1 since object B is new'ed from Derived class?
2. Why "Derived destructor" is called in Case 2 since only ~base() becomes
"virtual" and ~Derived() is still non-virtual?
3. Does Case 3 show that we don't need any virtual destructor to make
~Derived() called?
4. Is "virtual destructor" needed only for Case 2?
Case 1:
========

class base
{
public:
~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n"; }
};
int main(){
base* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Base destructor

Case 2:
========

class base
{
public:
virtual ~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n" }
};
int main () {

base* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Derived destructor
Base destructor

Case 3:
=========

class base
{
public:
~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n" }
};
int main () {

Derived* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Derived destructor
Base destructor


Jul 19 '05 #1
11 10443
"Stub" <st**@asof.com> wrote...
Please answer my questions below - thanks!

1. Why "Derived constructor" is called but "Derived destructor" not in Case 1 since object B is new'ed from Derived class?
Probably because there is no virtual destructor and you're deleting
the object through a pointer to class 'base', not 'Derived'. HOWEVER,
this behaviour is simply a chance occurrence because if destructor is
not virtual an attempt to delete an object of a derived type through
a pointer to a base class causes _undefined_behaviour_.
2. Why "Derived destructor" is called in Case 2 since only ~base() becomes
"virtual" and ~Derived() is still non-virtual?
The "since" part of the question is false. If the base class' d-tor
is virtual, all derived class' d-tors are virtual too.
3. Does Case 3 show that we don't need any virtual destructor to make
~Derived() called?
I suppose it does. If you delete it through the pointer to Derived,
there is no need in a virtual destructor.
4. Is "virtual destructor" needed only for Case 2?
No. Case 1 requires a virtual destructor. Without it the behaviour
of the Case 1 program is _undefined_.


Case 1:
========

class base
{
public:
~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n"; }
};
int main(){
base* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Base destructor

Case 2:
========

class base
{
public:
virtual ~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n" }
};
int main () {

base* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Derived destructor
Base destructor

Case 3:
=========

class base
{
public:
~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n" }
};
int main () {

Derived* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Derived destructor
Base destructor

Jul 19 '05 #2
"Stub" <st**@asof.com> wrote in message
news:Yo***********************@bgtnsc04-news.ops.worldnet.att.net...
Please answer my questions below - thanks!
I would, but this does look suspiciously like homework to me. We're all more
than happy to help with that if there's some evidence of an effort having
been made, but no-one here is going to do your homework for you. Besides,
I've got more than enough of my own... :-) FWIW, I'll explain the underlying
idea to you, and if you can figure out the answers to the questions from
that, then so much the better:

Given a base class B and a class D (publicly) derived from B, the following
scenario exhibits undefined behaviour iff B's destructor is non-virtual:

B *p = new D;
delete p;

(Interesting aside - The following always exhibits undefined behaviour,
whether or not B has a virtual destructor:
B *p = new D[5];
delete [] p;
)

This is essentially because the compiler merely invokes the destructor
associated with the static type of p (i.e. B's destructor) as it doesn't
realise it's supposed to invoke D's destructor. Much as:

class B
{
public:
void f() { std::cout << "B"; }
};

class D : public B
{
public:
void f() { std::cout << "D"; }
};

B *p = new D;
p->f();
....

will output B, since f is non-virtual. However, if we did:

D *q = new D;
q->f();
....

then it would output D, since q is a D *.

Hope that helped a bit, I'll let you figure out the rest for yourself.

Cheers,

Stuart.
1. Why "Derived constructor" is called but "Derived destructor" not in Case 1 since object B is new'ed from Derived class?
2. Why "Derived destructor" is called in Case 2 since only ~base() becomes
"virtual" and ~Derived() is still non-virtual?
3. Does Case 3 show that we don't need any virtual destructor to make
~Derived() called?
4. Is "virtual destructor" needed only for Case 2?
Case 1:
========

class base
{
public:
~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n"; }
};
int main(){
base* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Base destructor

Case 2:
========

class base
{
public:
virtual ~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n" }
};
int main () {

base* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Derived destructor
Base destructor

Case 3:
=========

class base
{
public:
~base() { cout << "Base destructor\n"; }
};
class Derived : public base
{
public:
Derived() { cout << "Derived constructor\n"; }
~Derived() { cout << "Derived destructor\n" }
};
int main () {

Derived* B = new Derived;
delete B;
return 0;
}

OUTPUT:
Derived constructor
Derived destructor
Base destructor

Jul 19 '05 #3
Victor Bazarov <v.********@comAcast.net> wrote in message
news:2Bxqb.131338$Tr4.337402@attbi_s03...
"Stub" <st**@asof.com> wrote...
Please answer my questions below - thanks!

1. Why "Derived constructor" is called but "Derived destructor" not in

Case
1 since object B is new'ed from Derived class?


Probably because there is no virtual destructor and you're deleting
the object through a pointer to class 'base', not 'Derived'. HOWEVER,
this behaviour is simply a chance occurrence because if destructor is
not virtual an attempt to delete an object of a derived type through
a pointer to a base class causes _undefined_behaviour_.
2. Why "Derived destructor" is called in Case 2 since only ~base() becomes "virtual" and ~Derived() is still non-virtual?


The "since" part of the question is false. If the base class' d-tor
is virtual, all derived class' d-tors are virtual too.

This is the part which confused me...

First, is Case 2 the right way to implement virtual destructor so that when
deleting an object of Derived type via its base class pointer, the
destructor in Derived will be called for sure?

Second, the virtual d-tor, "~base()", in base has a different function name
compared to the virtual d-tor in Derived, "~Derived()." How could it make
"~Derived()" automatically virtual here? Is there any overriding here given
their names different? Or is this just designed by C++ Standard. See, I am
just trying to understand the concept here.

Thanks for your help!
Jul 19 '05 #4
"Stub" <st**@asof.com> wrote...
Victor Bazarov <v.********@comAcast.net> wrote in message
news:2Bxqb.131338$Tr4.337402@attbi_s03...
"Stub" <st**@asof.com> wrote...
Please answer my questions below - thanks!

1. Why "Derived constructor" is called but "Derived destructor" not in Case
1 since object B is new'ed from Derived class?


Probably because there is no virtual destructor and you're deleting
the object through a pointer to class 'base', not 'Derived'. HOWEVER,
this behaviour is simply a chance occurrence because if destructor is
not virtual an attempt to delete an object of a derived type through
a pointer to a base class causes _undefined_behaviour_.
2. Why "Derived destructor" is called in Case 2 since only ~base() becomes "virtual" and ~Derived() is still non-virtual?


The "since" part of the question is false. If the base class' d-tor
is virtual, all derived class' d-tors are virtual too.

This is the part which confused me...

First, is Case 2 the right way to implement virtual destructor so that

when deleting an object of Derived type via its base class pointer, the
destructor in Derived will be called for sure?
Case 2 is fine.
Second, the virtual d-tor, "~base()", in base has a different function name compared to the virtual d-tor in Derived, "~Derived()."
It doesn't matter. It's a special function. Names here are not important.
How could it make
"~Derived()" automatically virtual here?
What's the difference _how_ it does that? The Standard requires it, so it
has to figure a way.
Is there any overriding here given
their names different? Or is this just designed by C++ Standard. See, I am just trying to understand the concept here.


The concept is this: for any class T if any of its base classes have their
destructor declared "virtual", the T's destructor is virtual, no ifs, ands
or buts.

Get a copy of the Standard, it's only $18 (in a PDF form). I strongly
recommend it.

Victor
Jul 19 '05 #5

"Stuart Golodetz" <st*************@new.ox.ac.uk> wrote in message
news:bo**********@news.ox.ac.uk...
"Stub" <st**@asof.com> wrote in message
news:Yo***********************@bgtnsc04-news.ops.worldnet.att.net...
[snip]

(Interesting aside - The following always exhibits undefined behaviour,
whether or not B has a virtual destructor:
B *p = new D[5];
delete [] p;
)


Stuart, you know better!. If the destructor is virtual, the code is OK.

See the code below and the output at the end

#include <iostream>

using namespace std;

class B
{
public:
virtual ~B()
{
cout << "B destructor\n";
}
};

class D : public B
{
public:
~D()
{
cout << "D destructor\n";
}
};
int main(int argc, char* argv[])
{
B *p = new D[5];

delete[] p;

return 0;
}
D destructor
B destructor
D destructor
B destructor
D destructor
B destructor
D destructor
B destructor
D destructor
B destructor

which is the right thing. (VC++ 6.0)

/dan
Jul 19 '05 #6
Dan Cernat wrote:
(Interesting aside - The following always exhibits undefined behaviour,
whether or not B has a virtual destructor:
B *p = new D[5];
delete [] p;
)
Stuart, you know better!. If the destructor is virtual, the code is OK.


No, it's not.
See the code below and the output at the end


Add a data member to D, and see what happens.

Max


Jul 19 '05 #7
"Max M" <ed***@maxim.comm2000.it> wrote in message
news:bo**********@newsreader.mailgate.org...
Dan Cernat wrote:
(Interesting aside - The following always exhibits undefined behaviour,
whether or not B has a virtual destructor:
B *p = new D[5];
delete [] p;
)


Stuart, you know better!. If the destructor is virtual, the code is OK.


No, it's not.
See the code below and the output at the end


Add a data member to D, and see what happens.


Interesting. Why is that?
--
Gary
Jul 19 '05 #8
Max M wrote in news:bo**********@newsreader.mailgate.org:
Dan Cernat wrote:
(Interesting aside - The following always exhibits undefined
behaviour, whether or not B has a virtual destructor:
B *p = new D[5];
delete [] p;
)


Stuart, you know better!. If the destructor is virtual, the code is
OK.


No, it's not.
See the code below and the output at the end


Add a data member to D, and see what happens.


Just for fun I did. I tried vc7.1 first and it worked just fine,
gcc 3.2 (MingW) seg' faulted and bcc called the B destructor 5 times
but no seg' fault (It probably would have if B's dtor had been more
complex, i.e. derefrenced this pointer in some significant way).

Clearly vc7.1 stores sizeof info in the poloymorfic type (or in its
vtable) and does "the right thing" when deleteing a polymorphic array.

AFAICT vc7.1's behaviour an extension to the standard, I really can't
imagine why they did it :).

FWIW here's the code:

#include <iostream>

using std::cerr;

int ctor = 0;

struct test
{
int data[10];

test()
{
for ( int i = 0; i < 10; ++i )
data[i] = 0x5AA55AA5;

data[1] = ++ctor;
}
~test()
{
cerr << "~test(" << data[1] << ")\n";
}
};

class B
{
public:
virtual ~B()
{
poly();
cerr << "B destructor\n";
}
virtual void poly() { cerr << "poly B\n"; }
};

class D : public B
{
test data_member;
public:
~D()
{
poly();
cerr << "D destructor\n";
}
virtual void poly() { cerr << "poly D\n"; }
};
int main()
{
B *p = new D[5];

delete[] p;
}

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 19 '05 #9
Max M <ed***@maxim.comm2000.it> wrote in message news:<bo**********@newsreader.mailgate.org>...
Dan Cernat wrote:
(Interesting aside - The following always exhibits undefined behaviour,
whether or not B has a virtual destructor:
B *p = new D[5];
delete [] p;
)


Stuart, you know better!. If the destructor is virtual, the code is OK.


No, it's not.
See the code below and the output at the end


Add a data member to D, and see what happens.

Max


I tried your suggestion and although I got the behaviour one would
expect (destruct of derived objects) I have to agree that it could
lead to undefined behaviour, especially if the pointer is passed
around and one tries to access its members (not at the index 0).
However, the memory manager seems that is doing the right job.

the new code:

#include <iostream>

using namespace std;

class InDerived
{
public:
~InDerived() {cout << "Destructor InDerived\n";}
};

class InBase
{
public:
~InBase() {cout << "Destructor InBase\n";}
};
class base
{
public:
InBase m_inBase;
virtual ~base() {cout << "Destructor base\n";}
};

class derived : public base
{
public:
InDerived m_inDerived;
int x;
~derived() {cout << "Destructor derived\n";}
};

void DeleteArray(base *p)
{
delete [] p;
}

int _tmain(int argc, _TCHAR* argv[])
{
base *p = new derived[5];

DeleteArray(p);
return 0;
}
Jul 19 '05 #10

"Dan Cernat" <dc*****@excite.com> wrote in message news:aa**************************@posting.google.c om...

I tried your suggestion and although I got the behaviour one would
expect (destruct of derived objects) I have to agree that it could
lead to undefined behaviour, especially if the pointer is passed
around and one tries to access its members (not at the index 0).
However, the memory manager seems that is doing the right job.


Not lead to undefined behavior, it is undefined behavior. Coincidentally
working is one of those insidious undefined behaviors. Try putting
some more data members in. It will be sure to break. The issue is not
just delete, you can ONLY convert the derived pointer of one object to
a base class. It doesn't work in arrays.

Image sizeof(base) is 4. sizeof(derived) is 8.
What is the relationship the base_array[1] with respect to base_array[0].
What is the relationship of derived_array[1] to derived_array[0].
Just think about it for a minute.
Jul 19 '05 #11

"Ron Natalie" <ro*@sensor.com> wrote in message
news:3f**********************@news.newshosting.com ...

"Dan Cernat" <dc*****@excite.com> wrote in message news:aa**************************@posting.google.c om...

I tried your suggestion and although I got the behaviour one would
expect (destruct of derived objects) I have to agree that it could
lead to undefined behaviour, especially if the pointer is passed
around and one tries to access its members (not at the index 0).
However, the memory manager seems that is doing the right job.


Not lead to undefined behavior, it is undefined behavior. Coincidentally
working is one of those insidious undefined behaviors. Try putting
some more data members in. It will be sure to break. The issue is not
just delete, you can ONLY convert the derived pointer of one object to
a base class. It doesn't work in arrays.

Image sizeof(base) is 4. sizeof(derived) is 8.
What is the relationship the base_array[1] with respect to base_array[0].
What is the relationship of derived_array[1] to derived_array[0].
Just think about it for a minute.

Yup, this is what I wanted to say in my prevoius message and I totally agree
with what you say.
I really should think twice before posting. Point taken.

Thanks,
Dan
Jul 19 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

39
by: Ele | last post by:
Is it correct to say that Whenever a class has a virtual member function, define its destructor as "virtual"? Can a destructor as "pure virtual"? When is it needed to do so? For an interface,...
11
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining...
37
by: WittyGuy | last post by:
Hi, I wonder the necessity of constructor and destructor in a Abstract Class? Is it really needed? ? Wg http://www.gotw.ca/resources/clcm.htm for info about ]
4
by: Tony Johansson | last post by:
Hello Experts!! Assume I have a base class called animal. I want this class to be abstract so I make the destructor pure virtual by having this statement. virtual ~Animal() = 0; Destructor...
26
by: pmizzi | last post by:
When i compile my program with the -ansi -Wall -pedantic flags, i get this warning: `class vechile' has virtual functions but non-virtual destructor, and the same with my sub-classes. But when i...
7
by: eric | last post by:
hello i'm confused by an example in the book "Effective C++ Third Edition" and would be grateful for some help. here's the code: class Person { public: Person(); virtual ~Person(); // see...
7
by: sam | last post by:
Hi, See when i reading a sourcecode of a program, I read that the constructor is ordinary and after that the programmer has written virtual destructor for that constructor . Why we use the...
3
by: GAURAV AGRAWAL | last post by:
Hi Guys, Can someone please explain me why this is happening #include<iostream> using namespace std; class a { public: int a1; // If I remove this it'll work fine
7
by: Tonni Tielens | last post by:
I'm trying to create a pure virtual class describing an interface. Normally, when I do this I make the destructor pure virtual so that, even if there are no members in the class, it cannot be...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
0
tracyyun
by: tracyyun | last post by:
Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.