一、单继承无函数覆盖
代码如下:
#include <stdio.h>
struct Base
{
public:
virtual void Function_1()
{
printf("Base:Function_1...\n");
}
virtual void Function_2()
{
printf("Base:Function_2...\n");
}
virtual void Function_3()
{
printf("Base:Function_3...\n");
}
};
struct Sub:Base
{
public:
virtual void Function_4()
{
printf("Sub:Function_4...\n");
}
virtual void Function_5()
{
printf("Sub:Function_5...\n");
}
virtual void Function_6()
{
printf("Sub:Function_6...\n");
}
};
void TestMethod()
{
//查看 Sub 的虚函数表
Sub sub;
//对象的前四个字节就是虚函数表
printf("base的虚函数表地址为:%x\n", *(int*)&sub);
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
pFunction pFn;
for (int i = 0; i < 6; i++)
{
int temp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)temp;
pFn();
}
}
int main()
{
TestMethod();
return 0;
}
可以看出,在单继承无函数覆盖的情况下,子类Sub继承父类Base,先调用父类的构造函数,输出顺序正常
二、单继承有函数覆盖
代码如下:
#include <stdio.h>
struct Base
{
public:
virtual void Function_1()
{
printf("Base:Function_1...\n");
}
virtual void Function_2()
{
printf("Base:Function_2...\n");
}
virtual void Function_3()
{
printf("Base:Function_3...\n");
}
};
struct Sub :Base
{
public:
virtual void Function_1()
{
printf("Sub:Function_1...\n");
}
virtual void Function_2()
{
printf("Sub:Function_2...\n");
}
virtual void Function_6()
{
printf("Sub:Function_6...\n");
}
};
void TestMethod()
{
//查看 Sub 的虚函数表
Sub sub;
//对象的前四个字节就是虚函数表
printf("base的虚函数表地址为:%x\n", *(int*)&sub);
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
pFunction pFn;
for (int i = 0; i < 4; i++)
{
int temp = *((int*)(*(int*)&sub) + i);
pFn = (pFunction)temp;
pFn();
}
}
int main()
{
TestMethod();
return 0;
}
子类Sub单继承父类Base,且子类覆盖了父类的函数Function_1和Function_2,而发现父类只有未被覆盖的Function_3能够输出,而Function_1和Function_2由于被子类覆盖,所以输出出来的是子类的Function_1和Function_2
但是子类只有在父类为virtual的时候才会覆盖父类
若将Function_1的virtual删掉,结果为:
我们可以发现,Function_2、Function_3还有Function_6照常,但是Function_1却是属于Sub类。
也就是说,子类函数只会覆盖父类的相应虚函数。
三、多继承无函数覆盖
#include <stdio.h>
struct Base1
{
public:
virtual void Fn_1()
{
printf("Base1:Fn_1...\n");
}
virtual void Fn_2()
{
printf("Base1:Fn_2...\n");
}
};
struct Base2
{
public:
virtual void Fn_3()
{
printf("Base2:Fn_3...\n");
}
virtual void Fn_4()
{
printf("Base2:Fn_4...\n");
}
};
struct Sub :Base1, Base2
{
public:
virtual void Fn_5()
{
printf("Sub:Fn_5...\n");
}
virtual void Fn_6()
{
printf("Sub:Fn_6...\n");
}
};
int main(int argc, char* argv[])
{
//查看 Sub 的虚函数表
Sub sub;
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
//对象的前四个字节是第一个Base1的虚表
printf("Sub 的虚函数表地址为:%x\n", *(int*)&sub);
pFunction pFn;
for (int i = 0; i < 6; i++)
{
int temp = *((int*)(*(int*)&sub) + i);
if (temp == 0)
{
break;
}
pFn = (pFunction)temp;
pFn();
}
//对象的第二个四字节是Base2的虚表
printf("Sub 的虚函数表地址为:%x\n", *(int*)((int)&sub + 4));
pFunction pFn1;
for (int k = 0; k < 2; k++)
{
int temp = *((int*)(*(int*)((int)&sub + 4)) + k);
pFn1 = (pFunction)temp;
pFn1();
}
printf("%x\n", sizeof(Sub)); //因为有两个直接父类,所以有两个虚函数表,总大小为8
return 0;
}
输出结果为:
可以看到,打印出来的Sub对象的大小为8,而一个指向虚函数表的地址的大小为4,也就是说,子类有多个直接父类的时候,就会出现对应父类数量的多个虚函数表
总结起来就是:由于有两个直接父类,所以Sub对象存储了两张虚函数表。第一张虚函数表存储了一个父类Base1的函数以及它的子类Sub的函数,第二张虚函数表存储了第二个父类Base2的函数
四、多继承有函数覆盖
#include <stdio.h>
struct Base1
{
public:
virtual void Fn_1()
{
printf("Base1:Fn_1...\n");
}
virtual void Fn_2()
{
printf("Base1:Fn_2...\n");
}
};
struct Base2
{
public:
virtual void Fn_3()
{
printf("Base2:Fn_3...\n");
}
virtual void Fn_4()
{
printf("Base2:Fn_4...\n");
}
};
struct Sub :Base1, Base2
{
public:
virtual void Fn_1()
{
printf("Sub:Fn_1...\n");
}
virtual void Fn_3()
{
printf("Sub:Fn_3...\n");
}
virtual void Fn_5()
{
printf("Sub:Fn_5...\n");
}
};
int main(int argc, char* argv[])
{
//查看 Sub 的虚函数表
Sub sub;
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
//对象的前四个字节是第一个Base1的虚表
printf("Sub 的虚函数表地址为:%x\n", *(int*)&sub);
pFunction pFn;
for (int i = 0; i < 6; i++)
{
int temp = *((int*)(*(int*)&sub) + i);
if (temp == 0)
{
break;
}
pFn = (pFunction)temp;
pFn();
}
//对象的第二个四字节是Base2的虚表
printf("Sub 的虚函数表地址为:%x\n", *(int*)((int)&sub + 4));
pFunction pFn1;
for (int k = 0; k < 2; k++)
{
int temp = *((int*)(*(int*)((int)&sub + 4)) + k);
pFn1 = (pFunction)temp;
pFn1();
}
return 0;
}
首先遍历第一张虚函数表,由于子类覆盖,所以先输出被子类覆盖的Fn_1,然后顺序输出父类的Fn_2,最后输出子类的Fn_5
然后遍历第二章虚函数表,先输出被子类覆盖的Fn_3,然后输出父类的Fn_4
五、多重继承无函数覆盖
#include <stdio.h>
struct Base1
{
public:
virtual void Fn_1()
{
printf("Base1:Fn_1...\n");
}
virtual void Fn_2()
{
printf("Base1:Fn_2...\n");
}
};
struct Base2 :Base1
{
public:
virtual void Fn_3()
{
printf("Base2:Fn_3...\n");
}
virtual void Fn_4()
{
printf("Base2:Fn_4...\n");
}
};
struct Sub :Base2
{
public:
virtual void Fn_5()
{
printf("Sub:Fn_5...\n");
}
virtual void Fn_6()
{
printf("Sub:Fn_6...\n");
}
};
int main(int argc, char* argv[])
{
//查看 Sub 的虚函数表
Sub sub;
//观察大小:虚函数表只有一个
printf("%x\n", sizeof(sub));
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
//对象的前四个字节是就是虚函数表
printf("Sub 的虚函数表地址为:%x\n", *(int*)&sub);
pFunction pFn;
for (int i = 0; i < 6; i++)
{
int temp = *((int*)(*(int*)&sub) + i);
if (temp == 0)
{
break;
}
pFn = (pFunction)temp;
pFn();
}
return 0;
}
多重继承无函数覆盖,先输出基类的函数,然后一代一代往下找,最后才输出到最后一个子类的函数
六、多重继承有函数覆盖
#include <stdio.h>
struct Base1
{
public:
virtual void Fn_1()
{
printf("Base1:Fn_1...\n");
}
virtual void Fn_2()
{
printf("Base1:Fn_2...\n");
}
};
struct Base2 :Base1
{
public:
virtual void Fn_3()
{
printf("Base2:Fn_3...\n");
}
};
struct Sub :Base2
{
public:
virtual void Fn_1()
{
printf("Sub:Fn_1...\n");
}
virtual void Fn_3()
{
printf("Sub:Fn_3...\n");
}
};
int main(int argc, char* argv[])
{
//查看 Sub 的虚函数表
Sub sub;
//观察大小:虚函数表只有一个
printf("%x\n", sizeof(sub));
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
//对象的前四个字节是就是虚函数表
printf("Sub 的虚函数表地址为:%x\n", *(int*)&sub);
pFunction pFn;
for (int i = 0; i < 6; i++)
{
int temp = *((int*)(*(int*)&sub) + i);
if (temp == 0)
{
break;
}
pFn = (pFunction)temp;
pFn();
}
return 0;
}
本文为参考滴水三期的学习笔记