【C++类与对象】多态

发布时间:2024年01月21日

基本概念

分类和区别

1、静态多态:函数重载和运算符重载属于静态多态,复用函数名。静态多态的函数地址早绑定-编译阶段确定函数地址
2、动态多态:派生类和虚函数实现运行时多态。动态多态的函数地址晚绑定-运行阶段确定函数地址

条件与使用

1、有继承关系
2、子类重写父类的虚函数(virtual
重写:函数返回值类型、函数名、参数列表完全一致

class Animal{
public: 
	//虚函数
	virtual void Speak() {
		cout << "动物说话" << endl;
	}
};
class Sheep :public Animal {
	void Speak() {
		cout << "羊在说话" << endl;
	}
};
class Dog :public Animal {
	void Speak() {
		cout << "狗在说话" << endl;
	}
};
//Speek没加virtual时地址早绑定,在编译阶段已经确定函数地址
void doSpeak(Animal& a) {//父类引用指向子类对象Animal &a=s1;
	a.Speak();
}
void test() {
	Sheep s1;
	doSpeak(s1);
	Dog d1;
	doSpeak(d1);
}

3、父类的指针或引用,执行子类对象

底层原理

指针占用四个字节。
在这里插入图片描述
父类:
在这里插入图片描述
在这里插入图片描述
子类:指针从父类继承
在这里插入图片描述
在这里插入图片描述

多态的优点

1、代码组织结构清晰
2、可读性强
3、利于前期和后期扩展和维护
4、开闭原则

//实现计算机抽象类
class AbstractC {
public:
	int a;
	int b;
	virtual int getResult() {
		return 0;
	}
};
//加法
class Add :public AbstractC {
public:
	int getResult(){
		return a+b;
	}
};
//-法
class Mul :public AbstractC {
public:
	int getResult(){
		return a - b;
	}
};
//*法
class Cheng :public AbstractC {
public:
	int getResult() {
		return a * b;
	}
};
///法
class Chu :public AbstractC {
public:
	int getResult() {
		return a / b;
	}
};
void test() {
	AbstractC* abc = new Add;
	abc->a = 10;
	abc->b=20;
	cout << "加法:" << abc->a << "+" << abc->b << "=" << abc->getResult() << endl;
	//用完销毁
	delete abc;

	abc = new Mul;
	abc->a = 10;
	abc->b = 20;
	cout << "减法:" << abc->a << "-" << abc->b << "=" << abc->getResult() << endl;
	//用完销毁
	delete abc;
	abc = new Cheng;
	abc->a = 10;
	abc->b = 20;
	cout << "乘法:" << abc->a << "*" << abc->b << "=" << abc->getResult() << endl;
	//用完销毁
	delete abc;
	abc = new Chu;
	abc->a = 10;
	abc->b = 20;
	cout << "加法:" << abc->a << "/" << abc->b << "=" << abc->getResult() << endl;
	//用完销毁
	delete abc;
}

纯虚函数和抽象类

纯虚函数语法:virtual 返回值类型 函数名 (参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类
特点:无法实例化对象,子类必须重写抽象类中的纯虚函数,否则也属于抽象类。让子类必须重写父类中的纯虚函数,否则不能实例化对象。

class AbsDrink {
public:
	virtual void Boil() = 0;
	virtual void Brew() = 0;
	virtual void Pour() = 0;
	virtual void Put() = 0;
	void make() {
		Boil();
		Brew();
		Pour();
		Put();
	}
};
class Coffee :public AbsDrink {
public:
	virtual void Boil() {
		cout << "煮咖啡" << endl;
	}
	virtual void Brew() {
		cout << "冲水" << endl;
	}
	virtual void Pour() {
		cout << "倒咖啡" << endl;
	}
	virtual void Put() {
		cout << "加小料" << endl;
	}
};
class Tea :public AbsDrink {
public:
	virtual void Boil() {
		cout << "煮清泉" << endl;
	}
	virtual void Brew() {
		cout << "冲茶水" << endl;
	}
	virtual void Pour() {
		cout << "倒茶" << endl;
	}
	virtual void Put() {
		cout << "加茶叶" << endl;
	}
};
void doWork(AbsDrink* a) {
	a->make();
	delete a;
}
void test() {
	doWork(new Coffee);
	cout << "--------------------------" << endl;
	doWork(new Tea);
}

虚析构和纯虚析构

多态使用时,若子类中有属性开辟到堆区中,父类指针在释放时无法调用到子类的析构代码,就需要将的父类中的析构函数改为虚析构和纯虚析构

共性和区别

1、可以解决父类指针释放子类对象
2、都需要有具体的函数实现
3、如果是纯虚析构,该类属于抽象类,无法实例化对象

父类指针在析构时,不会调用子类中析构函数,导致子类如果由堆区属性,出现了内存泄漏,虚析构可以解决
虚析构语法:virtual ~类名(){}
纯虚析构语法:virtual ~类名()=0;类名::~类名(){}

1、虚析构或纯虚析构是用来解决通过父类指针释放子类对象
2、如果子类没有堆区数据,可以不写
3、拥有纯虚析构函数的类也属于抽象类

class Animal {
public:
	//虚函数
	virtual void Speak() {
		cout << "动物说话" << endl;
	}
	Animal() {
		cout << "动物的构造函数" << endl;
	}
	/*虚析构,抽象类,无法实例化对象
	virtual ~Animal() {
		cout << "动物的析构函数" << endl;
	}*/
	//纯虚析构  需要声明也需要实现
	virtual ~Animal() = 0;
};
Animal::~Animal() {

}
class Sheep :public Animal {
public:
	string* name;
	Sheep(string _name) {
		name = new string(_name);
		cout << "羊的构造函数" << endl;
	}
	void Speak() {
		cout << "羊在说话" << endl;
	}
	~Sheep() {
		
		if (name != NULL) {
			cout << "羊的析构函数" << endl;
			delete name;
			name = NULL;
		}
	}
};
void doSpeak(Animal& a) {
	a.Speak();
}
void test() {
	Animal *a=new Sheep("羊");
	a->Speak();
	//父类指针在析构时,不会调用子类中析构函数,导致子类如果由堆区属性,出现了内存泄漏
	delete a;
}
文章来源:https://blog.csdn.net/qq_50563459/article/details/135722050
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。