473,324 Members | 2,124 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 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 10476
"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: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

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.