多态-c++ 2020 3 13

本文深入探讨C++中的多态概念,包括静态多态与动态多态的区别,虚函数的作用,以及如何通过父类指针调用子类的重写函数。通过具体案例,如计算器类的扩展和计算机组件的设计,展示了多态带来的代码结构清晰、可读性和可维护性的提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多态

在这里插入图片描述

class Animal
{
public:
	void speak()
	{
		cout << "动物在说话" << endl;
	}
};
class Cat: public Animal
{
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};
// 因为地址早绑定了 所以在编译阶段就确定了函数的地址
void doSpeak(Animal &animal)
{
	animal.speak();
}
void test01()
{
	Cat cat;
	doSpeak(cat);
}

int main()
{
	test01();
}
// 因为地址早绑定了 所以在编译阶段就确定了函数的地址 所以最后的输出结果为动物在说话

若想执行让猫说话 则这个函数地址就不可以提前绑定 需要在运行阶段再进行绑定

/* 动态多态的满足条件
1 有继承关系
2 子类重写父类的虚函数 重写(函数返回值的类型 函数名 参数列表 均要完全相同)
动态的多态使用
父类的指针或是引用 指向子类的对象
*/
class Animal
{
public:
	virtual void speak()// 函数面前加上virtual关键字 变成虚函数 那么编译器在编译的时候 就不能确定函数的地址了
	{
		cout << "动物在说话" << endl;
	}
};
class Cat: public Animal
{
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

void doSpeak(Animal &animal)
{
	animal.speak();
}
void test01()
{
	Cat cat;
	doSpeak(cat);
}

int main()
{
	test01();
}
// 运行结果为猫在说话

多态的原理

在这里插入图片描述
当基类中的成员函数变成了虚函数后 这个类中就会有一个虚函数(表)指针 指向的是虚函数的地址 当子类没有重写父类的虚函数的时候 就会继承父类的虚函数的指针 指针指向的是腐恶开中虚函数的地址 而当子类重写了父类的虚函数后 也会有一个指针 但是指向的已经不是父类中虚函数的地址了 而是子类中自己重写的那个函数的地址

多态案例

在这里插入图片描述
普通实现

class Calcular
{
public:
	int m_num1;
	int m_num2;
	int getresult(string opr)
	{
		if (opr == "+")
			return m_num1 + m_num2;
		else if (opr == "-")
		{
			return m_num1 - m_num2;
		}
		else if (opr == "*")
			return m_num1 * m_num2;
		
	}
	/* 如果想要去扩展新的功能 需要修改源码 
	而在真实的开发中 提倡开闭原则 
	也就是 对扩展进行开发 对修改进行关闭
	*/
};



void test01()
{
	Calcular c1;
	c1.m_num1 = 10;
	c1.m_num2 = 20;
	cout << "m_num1" << "+" << "m_num2 = " << c1.getresult("+") << endl;
}

int main()
{
	test01(); 
}

多态进行实现

class Calcular
{
public:
	int m_num1;
	int m_num2;
	virtual int result()
	{
		return 0;
	}
	
};
class AddCalcular : public Calcular 
{
public:
	int result()
	{
		return m_num1 + m_num2;
	}
};
class SubCalcular:public Calcular
{
public:
	int result()
	{
		return m_num1 - m_num2;
	}
};
class MulCalcular :public Calcular
{
public:
	int result()
	{
		return m_num1 * m_num2;
	}
};
/*多态的好处
1 组织结构清晰
2 可读性强
3 对于前期和后期扩展以及维护性很高
*/
void test01()
{
	AddCalcular c1;
	c1.m_num1 = 20;
	c1.m_num2 = 200;
	cout << c1.m_num1 << "+" << c1.m_num2 << "= " << c1.result();
}

int main()
{
	test01(); 
}

纯虚函数和抽象类

在这里插入图片描述

/*
抽象类的特点
1 无法实例化对象
2 抽象类的子类必须重写父类中的纯虚函数 否则也无法实例化对象 因为子类也会是抽象类
*/
class Calcular
{
public:
	int m_num1;
	int m_num2;
	//纯虚函数 
	virtual int result() = 0;
	
	
};
class AddCalcular : public Calcular 
{
public:
	int result()
	{
		return m_num1 + m_num2;
	}
};
class SubCalcular:public Calcular
{
public:
	int result()
	{
		return m_num1 - m_num2;
	}
};
class MulCalcular :public Calcular
{
public:
	int result()
	{
		return m_num1 * m_num2;
	}
};
/*多态的好处
1 组织结构清晰
2 可读性强
3 对于前期和后期扩展以及维护性很高
*/
void test01()
{
	//Calcular c1;错误 抽象类无法实例化对象
	//new Calcular; 错误 抽象类无法实例化对象
	AddCalcular c1;
	c1.m_num1 = 20;
	c1.m_num2 = 200;
	cout << c1.m_num1 << "+" << c1.m_num2 << "= " << c1.result() << endl;
	Calcular* c2 = new SubCalcular; // 通过父类的指针 指向子类的对象
	c2->m_num1 = 100;
	c2->m_num2 = 12;
	cout << c2->m_num1 << "-" << c2->m_num2 << "= " << c2->result() << endl;
	delete c2; // 内存记得释放
}

int main()
{
	test01(); 
}

多态案例2

在这里插入图片描述

class AbstractDrink
{
public:
	virtual void Biol() = 0;
	virtual void Brew() = 0;
	virtual void PourIncup() = 0;
	virtual void PutSomething() = 0;
	void MakeDrink()
	{
		Biol();
		Brew();
		PourIncup();
		PutSomething();
	}

};
class Coffee :public AbstractDrink
{
	virtual void Biol()
	{
		cout << "煮自来水" << endl;
	}
	virtual void Brew()
	{
		cout << "冲泡咖啡" << endl;
	}
	virtual void PourIncup()
	{
		cout << "倒入杯中" << endl;
	}
	virtual void PutSomething()
	{
		cout << "加入布丁" << endl;
	}
	void MakeDrink()
	{
		Biol();
		Brew();
		PourIncup();
		PutSomething();
	}
};
class Tea :public AbstractDrink
{
	virtual void Biol()
	{
		cout << "煮自来水" << endl;
	}
	virtual void Brew()
	{
		cout << "冲泡茶叶" << endl;
	}
	virtual void PourIncup()
	{
		cout << "倒入杯中" << endl;
	}
	virtual void PutSomething()
	{
		cout << "加入柠檬" << endl;
	}
	void MakeDrink()
	{
		Biol();
		Brew();
		PourIncup();
		PutSomething();
	}
};
void DoDrink(AbstractDrink* drink)
{
	drink->MakeDrink();
	delete drink; // 释放内存
}

void test01()
{
	DoDrink(new Coffee);
}
int main()
{
	test01(); 
}

虚析构和纯虚析构

在这里插入图片描述

class Animal
{
public:
	Animal()
	{
		cout << "Animal构造函数的调用" << endl;
	}
	virtual void Speak() = 0;
	//virtual ~Animal() // 利用虚析构可以解决父类指针释放子类对象时 内存泄露的问题
	//{
	//	cout << "Animal析构函数的调用" << endl;
	//}
	// 纯虚析构 需要声明 也需要实现 和纯虚函数不一样 纯虚函数只需要声明就好
	// 有了纯虚析构之后 就算这个类就没有纯虚函数  也属于抽象类 无法实例化对象
	virtual ~Animal() = 0;
};
Animal::~Animal()
{
	cout << "Animal纯虚析构函数的调用" << endl;
}
class Cat:public Animal
{
public:
	Cat(string name)
	{
		cout << "Cat构造函数的调用" << endl;
		m_name = new string(name);
	}
	void Speak()
	{
		cout << *m_name <<"这只小猫在说话" << endl;
	}
	string* m_name;
	 ~Cat()
	{
		cout << "Cat析构函数的调用" << endl;
		if (m_name != NULL) 
		{
			delete m_name;
			m_name = NULL;
		}
	}

};

void test01()
{
	Animal* c1 = new Cat("小灰");
	c1->Speak();
	// 父类指针在析构的时候 不会调用子类中的析构函数 导致如果子类中如果有堆区的数据 就会导致内存的泄露
	delete c1; 
}
int main()
{
	test01(); 
}

多态案例3

在这里插入图片描述

class CPU
{
public:
	virtual void calcular() = 0;
};
class VideoCard
{
public:
	virtual void display() = 0;
};
class Memory
{
public:
	virtual void storage() = 0;
};

class LenovoCPU : public CPU
{
public:
	void calcular()
	{
		cout << "联想的CPU正在计算" << endl;
	}
};
class LenovoVideoCard :  public VideoCard
{
public:
	void display()
	{
		cout << "联想的显卡正在工作" << endl;
	}
	
};
class LenovoMemory :  public Memory
{
public:
	void storage()
	{
		cout << "联想的内存正在储存" << endl;
	}

};

class InterCPU :public CPU
{
	void calcular()
	{
		cout << "因特尔的CPU正在计算" << endl;
	}
};
class InterVideoCard : public VideoCard
{
	void display()
	{
		cout << "因特尔的显卡正在工作" << endl;
	}
	
};
class InterMemory :public Memory
{
	void storage()
	{
		cout << "因特尔的内存正在储存" << endl;
	}
};

class AppleCPU :public CPU
{
	void calcular()
	{
		cout << "苹果的CPU正在计算" << endl;
	}
	
};
class AppleVideoCard : public VideoCard
{
	
	void display()
	{
		cout << "苹果的显卡正在工作" << endl;
	}
};
class AppleMemory : public Memory
{
	void storage()
	{
		cout << "苹果的内存正在储存" << endl;
	}
};

class Computer
{
public:
	Computer(CPU* c1, VideoCard* v1, Memory* m1)
	{
		m_c1 = c1;
		m_v1 = v1;
		m_m1 = m1;
	}
	
public:
	void DoWork()
	{
		m_c1->calcular();
		m_v1->display();
		m_m1->storage();
	}
	~Computer()
	{
		if (m_c1 != NULL)
		{
			delete m_c1;
			m_c1 = NULL;
		}
		if (m_v1 != NULL)
		{
			delete m_c1;
			m_v1 = NULL;
		}
		if(m_m1 != NULL)
		{
			delete m_c1;
			m_m1 = NULL;
		}
	}
private:
	CPU *m_c1;
	VideoCard *m_v1;
	Memory* m_m1;

};
	

void test01()
{
	CPU* cpu = new LenovoCPU;
	Memory* memo = new AppleMemory;
	VideoCard* vd = new InterVideoCard;
	Computer *cp = new Computer(cpu, vd, memo);
	cp->DoWork();
	delete cp;
}
int main()
{
	test01(); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值