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