class B{
public :
virtualvoid m1();
virtualvoid m2();
};
class D : public B{
virtualvoid m1();
}
一、C++的动态绑定使用vtable(虚成员函数表)来实现。vtable支持运行时查询,使系统可以将某一函数名绑定到vtable的特定入口地址。
例如上段代码的虚函数表为:
虚成员函数 入口地址 虚成员函数 入口地址
B::m1 0x7723
D::m1 0x99a7 //重定义的
B::m2 0x23b4
D::m2 0x23b4 //完全继承
由于系统执行虚函数时,要从对象的vtable找到函数入口地址,而且vtable是存储于对象的内存空间中。假如对象没有实例化,就找不到vtable。因此,构造函数不能是vittual。
但是,析构函数一般都需要加上virtual,假如定义Base *b = new Deriver; Deriver是Base的子类,并且~Base()不为virtual。那么当对象被注销时,系统只会调用~Base(),而不会调用~Deriver(),因为b是Base类型,已被静态绑定析构函数。如果基类或子类用new创建了内存空间,就必须通过析构函数销毁。因此必须使用vitual析构函数,实现动态绑定。
另外:从另一个角度也可以看出构造函数不能为虚函数,1,虚函数的作用在于通过父类的指针或者引用调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类或者引用去调用,因此就规定构造函数不能是虚函数。
二、构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它
但析构却不一定,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A" << endl;
}
~A()
{
cout << "~A" << endl;
}
};
class B:public A
{
public:
B()
{
cout << "B" << endl;
}
~B()
{
cout << "~B" << endl;
}
};
class C:public B
{
public:
C()
{
cout << "C" << endl;
}
~C()
{
cout << "~C" << endl;
}
};
int main()
{
A *b = new B;
cout << endl;
A *c = new C;
cout << endl;
delete b;
cout << endl;
delete c;
return 0;
}
析构函数加上 virtual 后:
本文探讨了C++中虚函数的实现机制及其在运行时动态绑定的应用,特别是对于析构函数的重要性。通过示例代码说明了如何通过虚析构函数确保派生类对象能正确释放资源。
4966

被折叠的 条评论
为什么被折叠?



