可以看到加了virtual关键字后,父类和子类的大小都变成了四字节,这是因为生成了虚函数指针,指针指向虚函数表,虚函数表存储了虚函数地址,继承了父类的子类重写了虚函数,虚函数表中的函数地址被替换,再次调用虚函数就是调用了子类的函数func。 2、虚析构 虚析构主要是为了解决子类中有属性开辟到堆区,父类指针调用...
如果基类的析构函数,我定义为虚析构(virtual ~A()),那这样多态失效的原因就更容易理解了: 因为此时对象析构的顺序是 先派生类析构->基类析构.在基类析构~A()中调用foo()之时,派生类对象就已经完蛋了,B中资源都已释放,如果实现多态而调用B::foo(),那将会有未定义行为.所以编译器没有那么做. 同理,构...
C++中的析构函数(Destructor) 点击打开在线编译器,边学边练 除了上一节讲到的类对象在创建时自动调用的构造函数,在对象销毁时也会自动调用一个函数,它也和类名同名,也没有返回值,名字前有一个波浪线~,用来区分构造函数,它的作用主要是用做对象释放后的清理善后工作。它就是析构函数。
虚析构的实现与虚函数一致,只需要在父类的析构函数前面加上关键字即可,只需要将前面代码中的Animal基类改成: 此时运行结果为: 可以看到此时的Cat正常析构,堆区数据被正常释放! 纯虚析构 与纯虚函数实现类似,将Animal基类做如下改动: 值得注意的是,纯虚析构必须在类外具体实现,否则将无法完成编译。拥有纯虚析...
将父类的析构函数改为虚函数,就可以避免这种情况。 程序运行截图: 从程序的运行结果可以看出,父类和子类的内存都被析构了。所以在使用多态时一定要将父类的析构函数定义成虚函数,从而避免内存泄露。
析构函数也可以是虚的,甚至是纯虚的。例如: class Father { public: virtual ~Father()=0; // 纯虚析构函数 }; 当一个类打算被用作其它类的基类时,它的析构函数必须是虚的。考虑下面的例子: class Father { public: Father() { ptra_ = new char[10];} ~Father() { delete[] ptra_;} // ...
将父类的析构函数改为虚函数,就可以避免这种情况。 1. //test.cpp 2. #include <iostream> 3. using namespace std; 4. 5. class father 6. { 7. public: 8. father() 9. { 10. new int; 11. } 12. 13. virtual~father() 14. { ...
用C语言模拟实现以上C++代码。首先定义一个存储函数指针的结构体VTable,作为 Shape类的虚函数表 ,其中定义了两个函数指针, 分别指向该类计算面积的函数和析构函数,只要目标函数的参数列表和返回类型与函数指针定义相同,其中void*相当于this指针: structVTable{double(*GetArea)(void*);void(*Destructor)(void*);};...
从构造函数和析构函数中调用虚函数并不是本身有什么错误。这种调用的语义是安全的。然而,经验表明这样的调用很少是必须的,很容易扰乱维护者,如果被新手使用会成为错误源。 Enforcement(实施建议) Flag calls of virtual functions from constructors and destructors. ...
虚析构函数也就是使用virtual修饰的虚函数,为了能够防止子类对象初始化父类指针过程中的所引发的析构问题,我们常常会把父类的析构函数写成虚析构函数。如下测试代码: 如果你将父类的析构函数改为虚析构函数,子类和父类的析构函数将都可以被调用有兴趣的可以去试试哦。 希望对大家有帮助! 另外如果你想更好的提...