C++虚函数详解
共 3985字,需浏览 8分钟
·
2021-09-02 03:25
01
—
C++虚函数探索
C++是一门面向对象语言,在C++里运行时多态是由虚函数和纯虚函数实现的,现在我们看下在C++中如何用虚函数实现多态。先来看一段代码。
// virtual_function.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base::constructor run" << std::endl;
}
virtual void fun1() {
std::cout << "Base::fun1 run" << std::endl;
}
virtual void fun2() {
std::cout << "Base::fun2 run" << std::endl;
}
virtual ~Base() {
std::cout << "Base::desconstructor run" << std::endl;
}
};
class Derive : public Base {
public:
Derive() {
std::cout << "Derive::constructor run" << std::endl;
}
void fun1() {
std::cout << "Derive::fun1 run" << std::endl;
}
void fun3() {
std::cout << "Derive::fun3 run" << std::endl;
}
~Derive() {
std::cout << "Derive::desconstructor run" << std::endl;
}
};
int main()
{
Derive* d = new Derive();
d->fun1();
d->fun2();
d->fun3();
delete d;
}
这段代码编译运行后输出了:
Base::constructor run
Derive::constructor run
Derive::fun1 run
Base::fun2 run
Derive::fun3 run
Derive::desconstructor run
Base::desconstructor run
这段代码里基类Base定义了虚函数fun1和fun2,派生类Derive有成员函数fun1和fun3,其中派生类覆盖了继承而来的基类虚函数fun1。在主函数里创建Derive类型对象指针d指向Derive类型对象。由于派生类Derive成员函数fun1覆盖了基类Base成员函数fun1,因此通过d调用fun1实际调用的是派生类Derive类的成员函数fun1,而继承而来的成员函数fun2没有被覆盖,则通过指针d调用fun2实际调用的是基类成员函数fun2。这里好像让看不出虚函数有什么作用,那么我们将主函数修改如下:
int main()
{
Base* b = new Derive();
b->fun1();
b->fun2();
delete b;
}
在程序里我们将创建一个基类指针b并指向的是派生类,并且调用delete释放内存时使用的是基类指针b。编译运行输出结果如下:
Base::constructor run
Derive::constructor run
Derive::fun1 run
Base::fun2 run
Derive::desconstructor run
Base::desconstructor run
带有虚函数的类称为虚基类,子类继承虚基类。在C++中虚基类有一个虚函数表指针保存虚函数表地址,而虚函数表保存函数地址,虚函数表并不在虚基类里,但是虚函数表指针在虚基类里,子类继承虚基类,子类也就有了虚函数表指针。那么C++是如何通过虚函数表和虚函数表指针实现多态呢?打开VS2019,并用管理员身份运行"2019开发人员命令提示符"工具,如下图所示:
输入:cl /d1 reportSingleClassLayoutXXX [filename],XXX表示类名,[filename]表示类所在的.cpp文件路径。这里我输入源文件的派生类名和源文件路径,回车输出如下:
在C++中有虚函数的类,其析构函数默认是虚析构函数,只要是虚函数就会在虚函数表里有相应的函数地址,因此派生类里的虚函数表指针vfptr指向的虚函数表vftable必然保存着派生类析构函数的地址,类的析构过程:从继承链的最底端到最顶端依次调用析构函数,因此delete b调用过程:通过虚函数表指针vfptr找到虚函数表vftable,再通过虚函数表找到派生类析构函数地址,调用析构函数。