virtual/non-virtual Destructor behavior with Inheritance

According to the C++ tutorial here,
a derived class inherits every member of a base class except:
-its constructor and its destructor
-its operator=() members
-its friends


I wrote some code to test something, and I want to understand the output.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
using namespace std;

struct Base
{
	char _;
	Base(){ cout << "Hi!" << endl; }
	virtual void Print(){ cout << "Base" << endl; }
	virtual ~Base(){ cout << "Bye!" << endl; }
};

struct SubA: public Base
{
	int a;
	SubA(){ cout << "Hey, there!" << endl; }
	void Print(){ cout << "SubA" << endl; }
	~SubA(){ cout << "See ya!" << endl; }
};

struct SubB: public Base
{
	double b;
	SubB(){ cout << "Hello, World!" << endl; }
	void Print(){ cout << "SubB" << endl; }
	~SubB(){ cout << "Goodbye, World!" << endl; }
};

int main()
{
	Base* Test1 = new Base;
	Base* Test2 = new SubA;
	Base* Test3 = new SubB;

	cin.sync();
	cin.ignore();

	Test1->Print();
	Test2->Print();
	Test3->Print();

	cin.sync();
	cin.ignore();

	delete Test1;
	delete Test2;
	delete Test3;

	cin.sync();
	cin.ignore();
}
Hi!
Hi!
Hey, there!
Hi!
Hello, World!

Base
SubA
SubB

Bye!
See ya!
Bye!
Goodbye, World!
Bye!


If I do not make the destructor of the Base class virtual, why does it only call the Base class destructors on the delete statements?
Last edited on
When a function is virtual, calling that function treats the class as to what its "actual" type is.

When a function is non virtual, calling it treats it as what it "appears" to be.

Example:

1
2
3
4
5
6
7
8
9
Base* foo = new SubA;

// since foo "actually" is a SubA, this will call SubA::VirtualFunction
foo->VirtualFunction();

// since foo "appears to be" a Base (it's a Base*, not a SubA*), the compiler
//  can't tell at compile time whether or not it actually points to a SubA
//  so this calls Base::NonVirtual
foo->NonVirtual();


Destructors are the same way:

1
2
3
4
5
6
Base* Test2 = new SubA;  // read:  no need to cast here

delete Test2;

// if Base's dtor is virtual, then the "actual" type's dtor is called (in this case:  SubA's dtor
//  but if it's not virtual, only Base's dtor is called because the object "appears to be" a Base. 
Thanks, that's some very useful information. :)
Topic archived. No new replies allowed.