构造/析构函数与虚函数的联系

目录

一、构造/析构函数能不能作为虚函数

1、构造函数不能作为虚函数

2、析构函数可以作为虚函数(建议用virtual修饰父类析构函数)

二、构造/析构函数能不能发生多态


一、构造/析构函数能不能作为虚函数

1、构造函数不能作为虚函数

虚函数表指针正确的初始化是发生在构造函数执行结束之后,所以构造函数是不能作为虚函数的,假设你不小心用virtual去修饰构造函数,编译器会直接报错。

class Base
{
public:
    
    virtual Base()
    {
        std::cout << "Base()" << std::endl;
    }
};

2、析构函数可以作为虚函数(建议用virtual修饰父类析构函数)

虚函数表指针初始化调用是在构造函数之后,析构之前,理论上是可以作为虚函数的,那么析构函数函数作为虚函数的作用在哪呢?先看以下的一段代码,一个很简单的多态实现:

class Base
{
public:

//    virtual Base()
    Base()
    {
        std::cout << "Base()" << std::endl;
    }

    /*virtual*/ ~Base()
    {
        std::cout << "~Base()" << std::endl;
    }

    virtual void func()
    {
        std::cout << "Base::func()" << std::endl;
    }
};

class Child : public Base
{
public:
    Child()
    {
        std::cout << "Child()" << std::endl;
    }

    ~Child()
    {
        std::cout << "~Child()" << std::endl;
    }

    virtual void func()
    {
        std::cout << "Child::func()" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Base *ret = new Child();

    delete ret;

    return a.exec();
}

可以很容易就看到,前两行结果是由于继承的关系,先执行父类的构造再执行子类的构造,但是析构并非是我们想要的结果,正确的结果应该是先进行子类的析构,再执行父类的析构,出现这种结果就是因为我们没有将父类Base的析构函数用virtual进行修饰,这样编译器就直接认为执行父类析构就完事了,并没有对ret指针所指向的实际对象进行析构,所以需要用virtual对父类的析构函数进行修饰。

二、构造/析构函数能不能发生多态

1、构造函数不能发生多态行为:构造函数执行时,虚函数表指针并未初始化;

2、析构函数也不能发生多态行为:析构函数执行前,虚函数表指针已被销毁掉。

总结:当构造函数和析构函数调用虚函数时,只会体现当前类中的虚函数实现内容;

class Base
{
public:

//    virtual Base()
    Base()
    {
        std::cout << "Base()" << std::endl;
        func();    //输出:Base::func()
    }

    virtual ~Base()
    {
        func();    //输出:Base::func()
        std::cout << "~Base()" << std::endl;
    }

    virtual void func()
    {
        std::cout << "Base::func()" << std::endl;
    }
};

class Child : public Base
{
public:
    Child()
    {
        std::cout << "Child()" << std::endl;
        func();    //输出:Child::func()
    }

    ~Child()
    {
        func();    //输出:Child::func()
        std::cout << "~Child()" << std::endl;
    }

    virtual void func()
    {
        std::cout << "Child::func()" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Base *ret = new Child();

    delete ret;

    return a.exec();
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值