构造函数和析构函数可以是虚函数吗
虚函数的调用通过虚表指针来指定,虚表指针包含在对象的内存空间中,它在构造函数调用后完成初始化;
析构函数可以且常常是虚函数
这个原理上就很好理解啦,因为此时 vtable 已经初始化了,完全可以把析构函数放在虚函数表里面来调用。
C++类有继承时,析构函数必须为虚函数。如果不是虚函数,则使用时可能存在内存泄漏的问题。
虚表存放在哪里
虚表是全局唯一的,放在全局数据区;
虚函数和纯虚函数区别
对象的内存大小计算
空类,大小占用为1;
有虚函数,虚表指针占用为4;
非static数据成员的占用;
需要考虑内存对齐的问题;
类的基本成员函数
默认构造函数;
析构函数;
赋值运算符重载;
拷贝构造函数;
基类和派生类,基类指针指向派生类对象
基类指针可以指向派生类对象,其中句柄类型也就是指针类型决定哪个类的函数被调用,如果是基类指针指向派生类,那么调用的函数还是基类的;
但是,如果有了virtual以后,调用哪个版本的virtual函数则由句柄指向的对象来决定;也就是虽然指向的还是句柄,但是句柄仍然会指向派生类对象的虚表;
如下所示,使用基类D指向派生类E,在创建时调用E的构造函数,然后递归调用基类构造函数;在销毁时,调用D的析构函数,然后递归调用基类的析构函数;
#include <iostream>
using namespace std;
// 基类和派生类的析构函数
class C{
public:
C(){
cout << "C constructor\n";
}
~C(){
cout << "C deconstructor\n";
}
};
class D: public C{
public:
D(){
cout << "D constructor\n";
}
~D(){
cout << "D deconstructor\n";
}
};
class E:public D{
public:
E(){
cout << "E constructor\n";
}
~E(){
cout << "E deconstructor\n";
}
};
int main(){
D* test = new E();
delete test;
return 0;
}
C constructor
D constructor
E constructor
D deconstructor
C deconstructor
如果析构函数是虚函数,则结果如下:
#include <iostream>
using namespace std;
// 基类和派生类的析构函数
class C{
public:
C(){
cout << "C constructor\n";
}
virtual ~C(){
cout << "C deconstructor\n";
}
};
class D: public C{
public:
D(){
cout << "D constructor\n";
}
~D(){
cout << "D deconstructor\n";
}
};
class E:public D{
public:
E(){
cout << "E constructor\n";
}
~E(){
cout << "E deconstructor\n";
}
};
int main(){
D* test = new E();
delete test;
return 0;
}
C constructor
D constructor
E constructor
E deconstructor
D deconstructor
C deconstructor