C++面向对象---虚函数&继承

一、单继承无函数覆盖

代码如下:

#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;
}

在这里插入图片描述

本文为参考滴水三期的学习笔记

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值