C++虚函数是通过虚表实现的,虚函数的地址记录在需表中,只对象完成构造完成后,虚函数的地址才最终确定。
构造函数中调用虚函数
基类先于派生类构造,所以构造时没法调用到派生类的虚函数,也就是说只能调用到自己,也就是虚函数失去多态功能。
析构函数调用虚函数
派生类先于基类析构,所以析构时基类没法调用到派生类的虚函数,同样只能调用到自己,虚函数也失去多态功能。
代码
#include <iostream>class Base
{
public:Base(){std::cout << "Base Construct. ";this->fun2("Base::Base");}virtual ~Base(){std::cout << "Base Destruct. ";this->fun2("Base::~Base");}virtual void fun(){std::cout << "Base::fun" << std::endl;}virtual void fun2(const char* caller){std::cout << "Base::fun2, caller: " << caller << std::endl;}
};class Derive : public Base
{
public:Derive(){std::cout << "Derive Construct. ";this->fun2("Derive::Derive");}~Derive() override{std::cout << "Derive Destruct. ";this->fun2("Derive::~Derive");}void fun2(const char* caller) override{std::cout << "Derive::fun2: caller: " << caller << std::endl;}void fun() override{std::cout << "Derive::fun" << std::endl;}
};int main()
{Base *p = new Derive;delete p;return 0;
}
运行结果:
Base Construct. Base::fun2, caller: Base::Base
Derive Construct. Derive::fun2: caller: Derive::Derive
Derive Destruct. Derive::fun2: caller: Derive::~Derive
Base Destruct. Base::fun2, caller: Base::~Base
在构造函数函数或者析构函数中调用虚函数,通常IDE会有警告,为了消除警告可以通过域名符号调用虚函数,此时相当于直接指定函数地址,不需要通过虚表所以不会有警告
class Base
{
public:Base(){std::cout << "Base Construct. ";Base::fun2("Base::Base"); // 虚函数}virtual ~Base(){std::cout << "Base Destruct. ";Base::fun2("Base::~Base"); // 虚函数}virtual void fun(){std::cout << "Base::fun" << std::endl;}virtual void fun2(const char* caller){std::cout << "Base::fun2, caller: " << caller << std::endl;}
};
类函数指针
当类函数指针指向一个虚函数时,同样会触发多态,并不会直接调用函数指针对应的函数
#include <iostream>class Base
{
public:virtual void fun(){std::cout << "Base::fun" << std::endl;}};class Derive : public Base
{
public:void fun() override{std::cout << "Derive::fun" << std::endl;}
};int main()
{Base *p = new Derive;p->fun();p->Base::fun();auto pBFun = &Base::fun;auto pDFun = &Derive::fun;(p->*pBFun)();((Derive*)p->*pDFun)();return 0;
}
结果
Derive::fun
Base::fun
Derive::fun
Derive::fun