单继承
1、一个类
#include <iostream>
using namespace std;
class A {
int a;
virtual void run() {
cout << 1 << endl;
}
};
如果是一个类的话,我们定义了一个虚函数,就会有虚表对应产生,该类记录虚表的地址(四个字节),我们输出sizeof(A)是8,如果不是虚函数就没有虚表对应产生。
如果对于该类并没有涉及到多态和虚函数,就不会存储虚表指针。
我们查看类A的虚表情况:
如果没有虚函数,类A只有一个a变量:
类A没有继承,也没有虚函数,所以没有对应的虚表。
2、B继承A
首先我们要明确,虚表是针对本类的,本类存储的虚表。这个类的虚表就直接确定了,跟指向这个类对象的指针没有什么关系。
class A {
int a;
virtual void run() {
cout << 1 << endl;
}
};
class B :public A{
int b;
void run() {
cout << 2 << endl;
}
virtual void run2() {
cout << 3 << endl;
}
}
上面是最简单的继承,A的虚表和刚刚分析的一样。我们分析B的虚表,它的sizeof是12字节,因为包含了a,b,虚表指针。
因为run函数实现了override,所以虚表中会有B中的run函数入口,run2函数入口。如图所示:
此时指向B对象的指针,调用run,run2都是B类的。
如果我们把B中的run函数删去。
如果把A中的virtual去掉:
跟虚函数无关的函数,不会出现在虚表里面,它不会进行动态绑定。
现在给我们一个类,我们可以去刻画它的虚表什么样子了:
(1)、基类较为简单,虚函数都放进去。
(2)、派生类的虚表,我们可以从结果来分析。
如果单独属于派生类,且是虚函数,那会出现在虚表里面。
如果单独属于基类,且是虚函数,会出现在虚表里面。
如果实现了多态,那么派生类的函数会出现在虚表里面。
多继承
1、简单多继承
class A {
int a;
virtual void run() {
cout << 1 << endl;
}
};
class B{
int b;
virtual void run() {
cout << 2 << endl;
}
};
class C :public B,public A {
void run() {
cout << 3 << endl;
}
};
多继承最简单的例子:
我们分析,C继承了A的a,B的b。
函数方面,实现了A和Brun函数的重写(多态)。
看过虚表之后,发现与单继承一致,只不过C不再试只有一个虚表。
C存储两个虚表,一个基于A,一个基于B,所以sizeof©为16。
分析多继承的时候,还是可以看成单继承。对每个父类和自己的关系进行逐个分析,如图所示都实现了run函数的重写。学会了单继承的分析,多继承分析方法一致。
2、复杂多继承(在上面基础上加上B:A)
分析方法同样可以根据结果进行分析,不做详细说明。
这个虚表和内存展示工具:
Vs自带的command prompt。我版本2017,直接可以搜索到。
还有推荐左耳朵耗子的博客:
https://blog.csdn.net/haoel/article/details/1948051