虽然构造函数不能被定义成虚函数,但析构函数可以定义为虚函数,一般来说,如果类中定义了虚函数,析构函数也应被定义为虚析构函数,尤其是类内有申请的动态内存,需要清理和释放的时候。如果析构函数是非虚的,释放时会造成child类的析构函数得不到执行,从而内存泄漏。析构函数定义为虚析构函数,这样base类和child类的析构函数都得到了执行,避免了内存泄漏。
虚析构函数调用规则:
★如果有一个基类的指针指向派生类的对象,并且想通过该指针delete派生类对象,系统将只会执行基类的析构函数,而不会执行派生类的析构函数。为避免这种情况的发生,往往把基类的析构函数声明为虚的,此时,系统将先执行派生类对象的析构函数,然后再执行基类的析构函数。
★如果基类的析构函数声明为虚的,派生类的析构函数也将自动成为虚析构函数,无论派生类析构函数声明中是否加virtual关键字。
#include<iostream>
using namespace std;
class Base
{
public:
Base():_str(new char[32])
{
cout<<"Base()"<<endl;
}
~Base()
{
delete []_str;
cout<<"~Base()"<<endl;
}
private:
char* _str;
};
class Derived:public Base
{
public:
Derived():Base(),_mstr(new char[32])
{
cout<<"Derived()"<<endl;
}
~Derived()
{
delete []_mstr;
cout<<"~Derived()"<<endl;
}
private:
char* _mstr;
};
int main()
{
Base* p = new Derived;
delete p;
return 0;
}
|
#include<iostream>
using namespace std;
class Base
{
public:
Base():_str(new char[32])
{
cout<<"Base()"<<endl;
}
virtual ~Base() //虚析构函数
{
delete []_str;
cout<<"~Base()"<<endl;
}
private:
char* _str;
};
class Derived:public Base
{
public:
Derived():Base(),_mstr(new char[32])
{
cout<<"Derived()"<<endl;
}
~Derived() //虚析构函数,virtual从继承结构中得来
{
delete []_mstr;
cout<<"~Derived()"<<endl;
}
private:
char* _mstr;
};
class DDerived:public Derived
{
public:
DDerived():Derived(),_mmstr(new char[32]) //构造函数只要调用自己直接父类的构造函数就好了
{
cout<<"DDerived()"<<endl;
}
~DDerived() //虚析构函数,virtual从继承结构中得来
{
delete []_mmstr;
cout<<"~DDerived()"<<endl;
}
private:
char* _mmstr;
};
int main()
{
Base* p = new Derived;
delete p;
cout<<endl;
Derived* p1 = new DDerived;
delete p1;
cout<<endl;
Base* p2 = new DDerived;
delete p2;
cout<<endl;
DDerived* p3 = (DDerived*)new Base;
delete p3;
return 0;
}
|
#include <iostream>
using namespace std;
class Base0
{
public:
Base0(){cout << "Base0()" << endl; }
~Base0(){cout << "~Base0() " << endl; }
virtual void func1()
{ cout << "Base0::func1()" << endl; }
virtual void func2()
{ cout << "Base0::func2()" << endl; }
};
class Base1 : public Base0
{
public:
Base1()
{
func1();
cout << "Base1()" << endl;
}
virtual void func1()
{ cout << "Base1::func1()" << endl; }
virtual void func2()
{ cout << "Base1::func2()" << endl; }
~Base1()
{
func2();
cout << "~Base1()" << endl;
}
};
|
class Sub : public Base1
{
public:
Sub()
{
func1();
cout << "Sub()" << endl;
}
~Sub()
{ cout << "~Sub()" << endl; }
#if 1 //0
virtual void func1()
{ cout << "Sub::func1()" << endl; }
#endif
virtual void func2()
{ cout << "Sub::func2()" << endl; }
};
int main(void)
{
Sub sub;
return 0;
}
|
//1 //0 // 本类没有func1,就去调用父类的 |
基派生的二义性:
#include <iostream>
using namespace std;
class Base
{
public:
Base():_pdata(new char[1])
{ cout<<"Base()"<<endl; }
virtual ~Base()
{
cout<<"~Base()"<<endl;
delete []_pdata;
}
private:
char * _pdata;
};
class Child : public Base
{
public:
Child():Base(),_pdata2(new char[1])
{ cout<<"Child()"<<endl; }
~Child()
{
cout<<"~Child()"<<endl;
delete []_pdata2;
}
private:
char * _pdata2;
};
int main()
{
Base * pb = new Child;
delete pb;
cout<<"sizeof(Base)="<<sizeof(Base)<<endl;
cout<<"sizeof(Child)="<<sizeof(Child)<<endl;
}
//基派生二义性
|
#include <iostream>
using namespace std;
class A
{
public:
virtual void a()
{ cout<<"A::a()"<<endl; }
virtual void b()
{ cout<<"A::b()"<<endl; }
virtual void c()
{ cout<<"A::c()"<<endl; }
};
class B
{
public:
virtual void a()
{ cout<<"B::a()"<<endl; }
virtual void b()
{ cout<<"B::b()"<<endl; }
void c()
{ cout<<"B::c()"<<endl; }
void d()
{ cout<<"B::d()"<<endl; }
};
class C : public A, public B
{
public:
virtual void a()
{ cout<<"C::a()"<<endl; }
void c()
{ cout<<"C::c()"<<endl; }
void d()
{ cout<<"C::d()"<<endl; }
};
int main()
{
C c;
//c.b(); //A,B都有b(),无法确定使用哪个,二义性 解决办法,c.B::b()
A *pa = &c;
pa->a(); //C::a()
pa->b(); //A,B都有b(),采用静态联编,A* 指针,所以A::b();
pa->c(); //c()在A中虚函数,B中普通函数,C中重定义,输出由指针的类型决定,
//由于A中为虚函数,根据规则,调用C::c()
cout<<endl;
B *pb = &c;
pb->a(); //C::a()
pb->b(); //无法确定调用版本,静态联编,pb类型为B,所以调用B::b()
pb->c(); //取决于pb类型B,调用B::c()
pb->d(); //B,C都为普通函数,C隐藏了基类中的d(),但是指针pb为B类型,调用B::d()
cout<<"pa = "<<pa<<endl;
cout<<"pb = "<<pb<<endl;
cout<<"sizeof(A) = "<<sizeof(A)<<endl;
cout<<"sizeof(B) = "<<sizeof(B)<<endl;
cout<<"sizeof(C) = "<<sizeof(C)<<endl; //继承两个基类,基类的虚函数表都要继承过来
cout<<endl;
C *pc = &c;
cout<<"pc = "<<pc<<endl;
pc->a(); //C::a()
pc->c(); //C::c()
pc->d(); //C::d()
return 0;
}
|
#include<iostream>
using namespace std;
class A
{
public:
virtual void a()
{
cout<<"a() in A"<<endl;
}
virtual void b()
{
cout<<"b() in A"<<endl;
}
virtual void c()
{
cout<<"c() in A"<<endl;
}
};
class B
{
public:
virtual void a()
{
cout<<"a() in B"<<endl;
}
virtual void b()
{
cout<<"b() in B"<<endl;
}
void c()
{
cout<<"c() in B"<<endl;
}
void d()
{
cout<<"d() in B"<<endl;
}
};
class C:public A,public B
{
public:
virtual void a()
{
cout<<"a() in C"<<endl;
}
void c()
{
cout<<"c() in C"<<endl;
}
void d()
{
cout<<"d() in C"<<endl;
}
};
|
int main()
{
C c;
//c.b(); //b()在A, B类中都定义为虚函数, C中没有无法确定使用哪个版本
c.B::b(); //解决办法
cout<<endl;
A* pA = &c;
pA->a();
pA->b(); //b()在A, B类中都是虚函数, C类中没有定义, 编译器无法确定使用
//哪个版本, 只能采用静态联编. 由于pA的类型是A *,所以输出: b() in A
pA->c(); //c()在A中为虚函数, B中为普通函数, C中进行了重定义. 此时输出
//取决于指针pA的类型A, 由于c()在A中为虚函数, 故按照虚函数的规则处理,输出c() in C
//pA->d(); //d只在B和C中有,静态联编
cout<<endl;
B* pB = &c;
pB->a(); //a()在A, B , C三个类中都是虚函数, 调用C类的c(), 输出: a() in C
pB->b(); //b()在A, B类中都是虚函数, C类中没有定义, 编译器无法确定使用
//哪个版本, 只能采用静态联编. 由于pB的类型是B *,所以输出: b() in B
pB->c(); //c()在A中为虚函数, B中为普通函数, C中进行了重定义. 此时输出
//取决于指针pB的类型B, 由于c()在B中为普通函数, 故按照普通函数的规则处理,输出c() in B
pB->d(); //d()在B, C类中都定义为普通函数, C中的d()会隐藏基类B中的d(),
//但pB类型为B *, 故输出d() in B
cout<<endl;
C* pC = &c;
pC->a(); //a()在A, B , C三个类中都是虚函数, 调用C类的c(), 输出: a() in C
//pC->b(); //b()在A, B类中都定义为虚函数, C中无法确定使用哪个版本,
//引起二义性错误. 解决: pC->B::b();
pC->c(); //c()在A中为虚函数, B中为普通函数, C中进行了重定义(?). 此时输//出取决于指针pC的类型C, c()在C中无论是虚函数还是普通函数, 都输出c() in C
pC->d(); //d()在B, C类中都定义为普通函数, C中的d()会隐藏基类B中的d(),
//但pC类型为C *, 故输出d() in C
return 0;
}
|