C++多态(一)

本文介绍了C++的多态性,包括静态多态(如函数重载)和动态多态(基于虚函数的晚绑定)。动态多态需要继承关系、子类重写父类虚函数以及父类指针或引用指向子类对象。文章详细解释了早绑定与晚绑定的区别,并探讨了多态的底层实现,涉及虚函数指针和虚函数表。
摘要由CSDN通过智能技术生成

多态的概念

静态多态

之前的课程学过的函数重载,或者运算符重载等。
属于早绑定,函数地址在编译阶段会确定下来。

动态多态

派生类和虚函数来实现的动态多态。
属于晚绑定,函数地址在运行时确定。

下面讲解的多态都属于动态多态

class Animal {
public:
	void action() {
		cout << "Animal action" << endl;
	}
};

class Cat : public Animal {
public:
	void action(){
		cout << "Cat action" << endl;
	}
};

//那么会执行Cat中的action还是Animal中的action呢?
void action(Animal& animal) {
	animal.action();
}

int main() {
	Cat cat;
	//这里传入的cat的子类, 函数action形参animal指向cat;
	action(cat);
	return 0;
}

即使传入的对象是Cat,但是打印的依然是 Animal action。在编译期间已经确定了函数地址,所以打印的只能是Animal的action。

晚绑定

如何让运行期间再确定函数地址呢?

class Animal {
public:
	virtual void action() {
		cout << "Animal action" << endl;
	}
};

仅需要在函数前面加上virtual,变成虚函数。此时再调用action(cat)时,就会打印Cat action。

总结

静态多态是指函数重载(或操作符重载),属于编译期间函数地址的早绑定(编译期间确定了函数地址)。
动态多态需要满足以下条件:

  • 有继承关系
  • 子类重写(方法名和参数完全一致)父类的函数
  • 父类指针或者引用指向子类的对象

早绑定和晚绑定

对于初学者对这两个概念不是很清楚,这里做一下简单的描述。

早绑定

就是编译器把代码编译成可执行文件(或静态库或动态库)时,在编译后的代码中生成的机器码(二进制)就会确定好执行的地址。
通过逆向编译为汇编语言伪代码(代码不是很准确,仅是方便理解)如下:
在这里插入图片描述> 这里红框中很明确的指出来了jmp(跳转到地址 1111),也就是action函数调用被编译器直接翻译成函数地址。

晚绑定

编译器无法确定函数地址,需要运行时才可以确定。
在这里插入图片描述> 可以看到红框中的jmp v2,v2是一个变量,只有运行时才给它赋值,所以地址是未知的,所以这里属于晚绑定。

多态的底层原理

class Animal {
public:
	void action() {
		cout << "Animal action" << endl;
	}
};

sizeof(Animal)的大小是多少呢?一个无成员变量的类对象的大小只有一个字节。

class Animal {
public:
	virtual void action() {
		cout << "Animal action" << endl;
	}
};

sizeof(Animal)的大小是多少呢?一个无成员变量的类对象的大小有4个字节。(32位编译器)

类结构

我们使用命令行提示工具,之前的文章已经多次介绍了如何使用。
在这里插入图片描述

我们可以看到Animal占用了4个字节,并且有一个成员变量是vfptr(虚函数指针virtual function pointer),这个虚函数指针指向了vftable(虚函数表 virtual function table),并且虚函数表中有一个函数地址&Animal::action

class Cat : public Animal {
public:
	void action(){
		cout << "Cat action" << endl;
	}
};

在这里插入图片描述

可以看到Cat继承了Animal的vfptr的指针,但是指向的vftable不一样,里面的函数地址是&Cat::action。

结论

这里再回顾一下为什么多态调用的是子类的方法呢?

Animal * animal = new Cat;
animal->action();

这里将会调用cat的action方法,因为animal中的vfptr指针指向的地址是Cat中的vftable,所以调用的时候就会使用Cat中的action。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诚学X

写作不易,请多鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值