以这段代码为例。
#include <iostream>
using namespace std;
class Parent
{
public:
	Parent()
	{}
	virtual void func1() {};
	virtual void func2() {};
};
class Child :public Parent
{
public:
	Child()
		:n(0)
		,Parent()
	{
		cout << "Child()" << endl;
	}
	virtual void func1() {};
	void func2() {};
	void func3() {};
private:
	int n;
};
int main()
{
	Child c;
	return 0;
}
 
1. 虚函数表
虚函数表在编译时创建
编译时,对于包含虚函数的类,编译器会自动先为各个类创建好它们各自的虚函数表,其中对于子类重写父类的虚函数等工作也都完成了。
类的函数(包括虚函数)存储在代码段;
类的虚函数表存储在数据区中。
2. 虚函数表指针_vftptr
虚函数表指针在运行时创建
实例化含虚函数的子类对象时,分以下几步走:
- 开辟内存空间
 - 构造父类
 - 在类的首地址处,填入编译时创建完毕的虚函数表的地址,即虚函数表指针
 - 进入类的构造函数,执行初始化列表
 - 执行构造函数body部分
 
就如上面那段代码,汇编语言:

⭕平时做题时经常遇到,在父类的构造函数中,通过指向子类的父类this指针,调用了虚函数,且子类中重写了该虚函数。但是,此时子类的虚函数表并未明确(虚函数表指针尚未填入),所以不会触发多态,还是会调用父类的虚函数。
 
补充:
初始化列表的初始化顺序与初始化列表顺序无关。
- 对于成员变量,按成员变量的声明顺序进行初始化。
 - 对于父类构造,按继承的声明顺序正向进行构造。
 
而对于子类调用析构后,自动调用父类的析构,对于多个父类,安装继承的声明顺序反方向进行析构。
#include <iostream>
using namespace std;
class Parent
{
public:
	Parent()
	{
		cout << "Parent()" << endl;
	}
	~Parent()
	{
		cout << "~Parent()" << endl;
	}
};
class Base
{
public:
	Base()
	{
		cout << "Base()" << endl;
	}
	~Base()
	{
		cout << "~Base()" << endl;
	}
};
class Child :public Parent, public Base
{
public:
	Child()
		:Base()
		,Parent()
	{
		cout << "Child()" << endl;
	}
	~Child()
	{
		cout << "~Child()" << endl;
	}
};
int main()
{
	Child c;
	return 0;
}
 




















