50.静态联编和动态联编,多态初识

静态多态和动态多态的区别就是函数地址是早绑定(静态联编)还是晚绑定(动态联编)。如果函数的调用,在编译阶段就可以确定函数的调用地址,并产生代码,就是静态多态(编译时多态),就是说地址是早绑定的。而如果函数的调用地址不能编译不能在编译期间确定,而需要在运行时才能决定,这这就属于晚绑定(动态多态,运行时多态)。

静态联编
地址早绑定 编译阶段绑定好地址
动态联编 
地址晚绑定 ,运行时候绑定好地址
多态
父类的引用或指针指向子类对象

多态原理解析
当父类中有了虚函数后,内部结构就发生了改变
内部多了一个 vfprt
virtual  function pointer 虚函数表指针
指向 vftable  虚函数表
父类中结构  vfptr     &Animal::speak
子类中 进行继承 会继承 vfptr  vftable
构造函数中 会将虚函数表指针 指向自己的虚函数表
如果发生了重写,会替换掉虚函数表中的原有的speak,改为 &Cat::speak
深入剖析,内部到底如何调用
((void(*)())  (*(int*)*(int*)animal))();
猫吃鱼的函数调用(编译器的调用)

多态的成立条件:
    有继承
    子类重写父类虚函数函数
     a) 返回值,函数名字,函数参数,必须和父类完全一致(析构函数除外)
     b) 子类中virtual关键字可写可不写,建议写
    类型兼容,父类指针,父类引用 指向 子类对象

main.cpp

// 41.多态.cpp : 定义控制台应用程序的入口点。
//

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

	virtual void eat()
	{
		cout << "动物在吃饭" << endl;
	}

};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}

	virtual void eat()
	{
		cout << "小猫在吃鱼" << endl;
	}
};

//调用doSpeak ,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址
//如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址
//动态联编,写法 doSpeak方法改为虚函数,在父类上声明虚函数,发生了多态
// 父类的引用或者指针 指向 子类对象
void doSpeak(Animal & animal) //Animal & animal = cat
{
	animal.speak();
}
//如果发生了继承的关系,编译器允许进行类型转换

void test01()
{
	Cat cat;
	doSpeak(cat);//class Animal的speak没有定义成虚函数的时候输出:动物在说话
	//class Animal的speak有定义成虚函数virtual的时候输出:小猫在说话

}


void test02()
{
	cout << "sizeof(Animal)====" << sizeof(Animal) << endl;
	//sizeof(Animal)====4
	//父类指针指向子类对象 多态
	Animal * animal = new Cat;

	animal->speak();//输出:小猫仔说话
	// *(int*)*(int*)animal 函数地址
	((void(*)()) (*(int*)*(int*)animal))();//最后的()是调用speak方法,输出:小猫仔说话

	//  *((int*)*(int*)animal+1)猫吃鱼的地址

	((void(*)()) (*((int*)*(int*)animal + 1)))();//最后的()是调用eat方法输出:小猫在吃鱼
}

int main(){

	//test01();

	test02();

	system("pause");
	return EXIT_SUCCESS;
}

EXE2:

//抽象制作饮品
class AbstractDrinking{
public:
	//烧水
	virtual void Boil() = 0;
	//冲泡
	virtual void Brew() = 0;
	//倒入杯中
	virtual void PourInCup() = 0;
	//加入辅料
	virtual void PutSomething() = 0;
	//规定流程
	void MakeDrink(){
		Boil();
		Brew();
		PourInCup();
		PutSomething();
	}
};

//制作咖啡
class Coffee : public AbstractDrinking{
public:
	//烧水
	virtual void Boil(){
		cout << "煮农夫山泉!" << endl;
	}
	//冲泡
	virtual void Brew(){
		cout << "冲泡咖啡!" << endl;
	}
	//倒入杯中
	virtual void PourInCup(){
		cout << "将咖啡倒入杯中!" << endl;
	}
	//加入辅料
	virtual void PutSomething(){
		cout << "加入牛奶!" << endl;
	}
};

//制作茶水
class Tea : public AbstractDrinking{
public:
	//烧水
	virtual void Boil(){
		cout << "煮自来水!" << endl;
	}
	//冲泡
	virtual void Brew(){
		cout << "冲泡茶叶!" << endl;
	}
	//倒入杯中
	virtual void PourInCup(){
		cout << "将茶水倒入杯中!" << endl;
	}
	//加入辅料
	virtual void PutSomething(){
		cout << "加入食盐!" << endl;
	}
};

//业务函数
void DoBussiness(AbstractDrinking* drink){
	drink->MakeDrink();
	delete drink;
}

void test(){
	DoBussiness(new Coffee);
	cout << "--------------" << endl;
	DoBussiness(new Tea);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值