C++ 类和虚函数

本文探讨了C++中构造函数和析构函数的特性。构造函数不应该是虚函数,因为虚函数表在构造过程中初始化,而析构函数通常应当是虚函数以确保正确地销毁派生类对象。当基类指针指向派生类对象时,非虚析构函数可能导致内存泄漏。虚函数表(vtable)在对象内存中存放一个指针,并且对于有继承关系的类,析构函数必须为虚函数。文章还涉及了对象内存大小的计算,包括空类、虚函数和数据成员的影响,以及内存对齐等概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造函数和析构函数可以是虚函数吗

虚函数的调用通过虚表指针来指定,虚表指针包含在对象的内存空间中,它在构造函数调用后完成初始化;

析构函数可以且常常是虚函数

这个原理上就很好理解啦,因为此时 vtable 已经初始化了,完全可以把析构函数放在虚函数表里面来调用。

C++类有继承时,析构函数必须为虚函数。如果不是虚函数,则使用时可能存在内存泄漏的问题。

虚表存放在哪里

C++ 虚函数表及多态内部原理详解(一)

虚表是全局唯一的,放在全局数据区;

虚函数和纯虚函数区别

知乎-C++ 虚函数、纯虚函数

对象的内存大小计算

C++类所占内存大小计算_大副的博客-CSDN博客

空类,大小占用为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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值