C++多态以及通过C语言实现多态

最近要开始准备实习了,所以需要对之前学过的知识做一些总结和回顾,最近发的博客可能更多的是对一些概念的理解。

通过C语言实现C++多态

一.C++多态的原理

在C++中,多态机制是通过虚表以及虚表指针来实现的。

我们都知道,当要实现多态功能的时候,都会通过virtual关键字来讲基类中的函数变为虚函数,然后通过子类继承后重写就能够达到多态的效果。但是实际上,在其中,编译器也为我们做了很多的工作。

1.当编译器发现基类中存在虚函数的时候,他会自动的生成一份虚表,在虚表中,存放的就是我们这些虚函数的入口地址。

2.当我们实例化一个带有虚函数对象的时候,编译器会给我们这个对象的前四个字节加一个虚表指针,指向我们上一步中生成的虚表,这也就是为什么当我们对一个存在虚函数的对象sizeof的时候,它的大小会比它的类成员变量总和大四个字节的原因。

3.当我们实例化一个派生类的时候,肯定是会先调用构造函数,这里还需要插入一些知识,我们都知道,当我们定义某个基类的时候,通常的做法是将这个基类的析构函数变为virtual的,也就是虚析构函数,因为在一般的情况下,我们会使用一个基类指针来接收子类对象,当我们释放这个基类指针的时候,就会自动调用我们子类的析构函数,但是假如不定义为虚析构函数的话,就可能导致只调用基类析构函数,从而导致子类析构不完全引发内存泄漏,原因之后会讲。现在回归正题,那我们一定会有疑惑为什么不将子类构造函数设置为虚函数呢?因为从我们上述的第二步我们可以看到,当我们实例化一个对象的时候之后,我们才会有一个虚表指针来指向我们生成的虚表,那么如果我们讲构造函数定义为虚函数的话,编译器要通过虚表指针来访问虚表,但是此时连虚表、虚表指针都没有,因此就会导致报错。现在回归正题,当我们实例化一个派生类的时候,首先会调用的就是基类的构造函数,当基类构造完全后,我们会有一个虚表以及一个基类的虚表指针,指向基类的虚表;进一步我们会调用子类的构造函数,构造完成之后就会有一个虚表指针来指向子类的虚表。

4.这样当我们使用基类指针来接收子类对象的时候,虚表指针就会指向子类的虚表,当我们调用对应的虚函数的时候,就会去虚表中查找从而调用,这样子就完成了多态。

具体多态就不演示了。

二.C语言实现多态

首先我们要明确,我们实现的多态是在运行时,通过父类指针来调用子类中的虚函数。因此首先我们先定义一个函数指针,来代表我们之前所描述的虚函数。

typedef void(*Fun) ();

在定义时,为了描述所谓的继承关系,我们先通过含有has-A的方式来使得C中的结构体能有一种逻辑上的继承关系,在如下所描述的代码中,我们的基类中含有一个函数指针,同样的我们的子类中含有一个父类对象,也就是说我们的子类中也有一个函数指针。

struct Father {
	Fun fun;	
};

struct Son {
	struct Father f;
};

接下来我们来实现所谓的重写,也就是通过函数指针来定义不同的行为:

void funF() {
	printf("this is father fun\n");
}

void funS() {
	printf("this is son fun\n");
}

然后我们开始我们的常规操作,也就是说,通过父类指针来接收子类对象,当调用父类指针的虚函数的时候,也就是我们如上所描述的函数指针的时候,会产生多态的效果。

void Test1() {
	struct Father f;
	struct Son s;
	//对应的重写
	f.fun = funF;
	s.f.fun = funS;
	
	struct Father* p1 = &f;
	//父类指针接收子类对象 
	struct Father* p2 = (struct Father*)&s;
	p1->fun();
	p2->fun();
}

最终结果如下所示:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值