绝不在构造和析构过程中调用virtual函数

绝不在构造和析构过程中调用virtual函数

Never call virtual function during construction or destruction

开始之间先说一个结论来开门见山!!绝对不要在构造和析构中调用virtual函数。这会导致发生不是你期望的事情。

比如,我们举个栗子!?

游戏我们都玩过吧,就好比MOBA类游戏。你击杀敌人和敌人把你击杀,都会有记录。那么来看看下面这个实现:

#include <iostream>

class Game {
public:
    Game();
    ~Game();
    virtual void Log() const = 0;

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

class Kill : public Game {
public:
    virtual void Log() const override {
        std::cout << "Kill Log()" << std::endl;
    }
};

class BeKill : public Game {
public:
    virtual void Log() const override {
        std::cout << "BeKill Log()" << std::endl;
    }
};

int main(void)
{
    Kill a;

    return 0;
}

在这里插入图片描述

首先,结果在运行时报错了。

因为这样创建对象时,派生类会先会调用基类的默认构造函数,然后,你基类的默认构造函数里面调用的虚函数,其实就是基类的虚函数。

说白了,就是你想通过派生类调用一下虚函数,结果调成了基类的虚函数,然后就报错了。

这是因为在linux平台下的gcc编译器报错。在其他平台下的其他编译器说不定不会报错(因为effective C++提出这个观点,说不定作者用的编译器没有报错呢)。试想想如果没有报错,那是不是就造成了一个错误。以后改的时候会比较麻烦。

析构函数也一样,如果你在析构函数里调用虚函数,那就会调用基类的虚函数。

然后你可能会说:卧槽这么明显的错误我怎么会犯呢?嘘~射程范围内。

试想下面的场景,假设这个基类里面有很多构造函数,那么我们每个构造函数虽然功能或接受参数不是那么完全相同,但是里面都要重复的初始化一些相同的成员变量,这些重复的代码会造成代码量过大,这样我们可以定义一个

init()函数,来初始化这相同的部分,那么如果,这个虚函数不是纯虚函数,并且这个init()还调用了它,此时就不会报错,还不容易被发现。等你定义了派生类对象之后,你就会发现,这个虚函数并不是你想要的,你也不知道怎么回事。

根据我的实验,之前那么报错只是因为虚函数被定义成了纯虚函数,没有实体连接不到。

#include <iostream>

class Game {
public:
    Game(){
        init();
    };

    void init() {
        Log();
    }

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

    virtual void Log() const {
        std::cout << "Game() Log()" << std::endl;
    }

};

class Kill : public Game {
public:
    virtual void Log() const override {
        std::cout << "Kill Log()" << std::endl;
    }
};

class BeKill : public Game {
public:
    virtual void Log() const override {
        std::cout << "BeKill Log()" << std::endl;
    }
};

int main(void)
{
    Kill a;

    return 0;
}

在这里插入图片描述

看吧。你本来想调用该对象类的Log()函数来初始化,结果调成了基类的Log()函数了。

解决办法:

唯一的一个解决办法就是,确定你的构造函数个析构函数里面没有调用虚函数!唯一!的!办法!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值