类和对象-多态

1.多态的基本概率:多态分为两类
  1.静态多类:函数重载(函数名相同,函数的参数不同)和运算符重载属于静态多态,复用函数名
    2.动态多态:派生类和虚拟函数实现运行时多态

静态多类和动态多态的区别:静态多态的函数地址早就绑定,编译阶段确定函数地址
                                    动态多态的函数地址晚绑定,运行阶段确定函数地址

#include<iostream>
using namespace std;

class Animal //动物类
{
public:
	virtual void speak()//虚函数:动态多态的函数地址晚绑定,运行阶段确定函数地址
	{
		cout << "动物在说话" << endl;
	}
};
class Cat: public Animal //猫类
{
public:
	void speak() // 这一步重写虚函数 此时vfptr指向了 cat的虚函数的地址
			//什么叫重写: 函数名 函数类型  参数值完全相同!!
	{
		cout << "小猫在说话" << endl;
	}
};
/*
1.如果我们希望传入什么对象,那么就调用什么对象的参数
2.如果函数地址在编译阶段才能确定,那么是静态编译
3.如果函数地址在运行阶段才能确定,那么是动态编译
*/
void Dospeak(Animal & animal) // Animal & animal = cat
{
	animal.speak();
}
/*
多态满足的条件:
1.有继承关系
2.子类重写父类中的虚函数(virtual)
多态的使用:
父类指针过应勇指向子类的对象
*/
void test01()
{
	Cat cat;
	Dospeak(cat);//我们原本的意思是想让小猫说话,编译的结果是 动物说话 与我们预期的结果不符合
}			//如果想执行小猫说话,那么地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定,就要运用多态来进行实现
int main() {
    test01();
    return 0;
}

虚函数的实现原理:


总结:
多态的使用必须满足:1.有继承关系 2.子类重写父类的虚函数
多态的使用条件:父类的指针或者引用指向子类对象 (Animal & animal) = cat
重写的概念:
        函数的返回类型 函数名 列表参数完全一致称为重写
2.多态案例—实现简易的计算器
分别利用普通写法和多态技术,设计实现两个操作数的计算器类

 

多态的优点:
1.代码组织结构清晰
2.可读性强
3.利于前期和后期的拓展以及维护


#include<iostream>
using namespace std;
#include<string>
//普通写法实现计算器
class Cacolator
{
public:
	int getresult(string oper)
	{
		if (oper == "+") { return a + b; }
		else if (oper == "-") { return a - b; }
		else if (oper == "*") { return a * b; };
	}    //如果想要扩展新的功能,需要修改源码
		//真实的开发中讲究开闭原则  对拓展进行开发,对修改进行关闭
	int a;
	int b;
};
void test01() {
	Cacolator c1;
	c1.a = 10;
	c1.b = 10;
	cout << c1.a << "+" << c1.b << "=" << c1.getresult("+") << endl;
	cout << c1.a << "-" << c1.b << "=" << c1.getresult("-") << endl;
	cout << c1.a << "*" << c1.b << "=" << c1.getresult("*") << endl;
}
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
//利用多态进行实现
class AbstractCacolator
{
public:
	virtual int getResult( )
	{
		return 0 ;
	}
	int m_a;
	int m_b;
};
//加法类
class AddCacoltor :public AbstractCacolator
{
public:
	int getResult()
	{
		return m_a + m_b;
	}
		//int m_a;
		//int m_b;  报错的原因!!!!!!!!!!它已经继承了父类的了
};
class SubCacoltor :public AbstractCacolator
{
public:
	int getResult()
	{
		return m_a - m_b;
	}
};
void test02()
{
	AbstractCacolator * p = new AddCacoltor;//手动在堆区开辟了内存 用完记得删除
	p->m_a = 100;
	p->m_b = 100;
	cout << p->m_a << "+" << p->m_b << "=" << p->getResult() << endl;
	delete p;

	p = new SubCacoltor;
	p->m_a = 100;
	p->m_b = 100;
	cout << p->m_a << "-" << p->m_b << "=" << p->getResult() << endl;
	delete p;

}
int main() 
{ 
	//test01();
	test02();
	 return 0;
}

3.多态的纯虚函数
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
 因此可以将虚函数改为纯虚函数

 纯虚函数的写法: virtual 返回值类型 函数名(参数列表) =0

 当类中有了纯虚函数 这个类也称为 抽象类
 抽象类的特点:1.无法实例化对象
                        2.子类必须重写抽象类的纯虚函数,否则也属于抽象类


#include<iostream>
using namespace std;
class Base
{
public:
	virtual void fun() = 0; //纯虚函数
};
class son :public Base
{
public:
	virtual void fun() //需要重写虚函数
	{
		cout << "  fun()函数调用  " << endl;
	}
};
void test01()
{
	Base * p = new son;
	p->fun();

}
int main()
{
	test01();
	//test02();
	return 0;
}

4.多态的案例

#include<iostream>
using namespace std;


class Makedrink
{
public://煮水
	virtual void boil() = 0;
	//冲泡
	virtual void brew() = 0;
	//倒入杯中
	virtual void cup() = 0;
	//加入辅料
	virtual void putsomething() = 0;

	//制作饮品
	void dowork()
	{
		boil();
		brew();
		cup();
		putsomething();
	}
};

class tea :public Makedrink
{
public:
	virtual void boil() { cout << "煮龙湖山泉" << endl; }		//煮水
	virtual void brew() { cout << "放入普洱茶" << endl; }		//冲泡
	virtual void cup() { cout << "倒入茶杯" << endl; }			//倒入杯中
	virtual void putsomething() { cout << "放点柠檬" << endl; }//加入辅料
};
void Dowork(Makedrink * abs)// Makedrink * abs = tea
{		//多态的使用条件:父类的指针或者引用指向子类对象 (Animal & animal) = cat
	abs->dowork();
	delete abs;
}

void test()
{
	Dowork(new tea); //如果我们希望传入什么对象,那么就调用什么对象的参数
}
int main()
{
	test();
	return 0;
}

5.多态的虚析构和纯虚析构
多态在使用的时候,如果子类有属性开辟到堆区!!!!! 那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构的共性:
1.可以解决父类指针释放子类对象
2.都需要具体函数的实现

区别:
如果是纯虚析构,哪么该类属于抽象类,无法实例化对象

虚析构语法:
virtual ~ 类名 (){}

纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
 


#include<iostream>
#include<string>
using namespace std;

class Animal
{
public:
	Animal()
	{
		cout << "Animal的构造函数"<<endl;
	}
	/*virtual ~Animal()//虚析构
	{
		cout << "Animal的析构函数" << endl;
	}*/

	//纯虚析构		如果是纯虚析构,哪么该类属于抽象类,无法实例化对象
	virtual ~Animal() = 0;

	virtual void speak() = 0;
};
Animal::~Animal()//必须得有纯虚析构的实现
{
	cout << "Animal的纯虚析构函数" << endl;
}
class Cat :public Animal
{public:
	Cat(string name)
	{
		cout << "cat的构造函数" << endl;
		m_name = new string(name); //开辟到堆区 
		//多态在使用的时候,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,就是为了解决这个问题
	}

	virtual void speak()
	{
		cout <<*m_name<< "小猫在说话" << endl;
	}
	string *m_name;
	~Cat()
	{
		if (m_name != NULL)
		{
			delete m_name;
			m_name = NULL;
		}
		cout << "cat的析构函数" << endl;
	}

};
void test()
{
	Animal * p = new Cat("Tom");
	p->speak();
	delete p;
}
int main()
{
	test();
	return 0;
}

6.多态案例:计算机

#include<iostream>
using namespace std;

class Cpu{ //Cpu类
public:
	virtual void caculate() = 0;//纯虚函数
};

class Videcard{ //显卡类
public:
	virtual void display() = 0;
};
class Memory { //内存条
public:
	virtual void storage() = 0;
};
class Computer 
{
public:
	Computer(Cpu* cpu, Videcard* videcard, Memory* memory)
	{	//父类的指针指向子类的对象 体现多态的技术
		m_Cpu = cpu;
		m_Memory = memory;
		m_Videcard = videcard;

	}
	void Dowork()
	{
		m_Cpu->caculate();
		m_Videcard->display();
		m_Memory->storage();
	}
	~Computer()
	{   //进行内存释放
		if (m_Cpu != NULL) { delete m_Cpu; m_Cpu = NULL; }
		if (m_Videcard != NULL) { delete m_Videcard; m_Videcard = NULL; }
		if (m_Memory != NULL) { delete m_Memory; m_Memory = NULL; }
	}
private:
	Cpu * m_Cpu;
	Videcard * m_Videcard;
	Memory * m_Memory;
};
//intel的零件
class IntelCpu :public Cpu
{ 
public:
	void caculate()
	{
		cout << "Intel的cpu正在计算" << endl;
	}
};
class IntelVidecard :public Videcard
{
public:
	void display()
	{
		cout << "Intel的videcard正在显示" << endl;
	}
};
class IntelMemory :public Memory
{
public:
	void storage()
	{
		cout << "Intel的Memory正在存储" << endl;
	}
};
//Lenove的零件
class LenoveCpu :public Cpu
{
public:
	void caculate()
	{
		cout << "Lenove的cpu正在计算" << endl;
	}
};
class Lenovevidecard :public Videcard
{
public:
	void display()
	{
		cout << "Lenove的videcard正在显示" << endl;
	}
};
class LenoveMemory :public Memory
{
public:
	void storage()
	{
		cout << "Lenove的Memory正在存储" << endl;
	}
};

void test()
{ //开始组装第一台电脑
	cout << "组装第一台intel的电脑" << endl;
	Computer* computer1 = new Computer(new IntelCpu, new IntelVidecard, new IntelMemory);
	//堆区开辟的内存记得释放,三个零件的在类中使用了析构函数进行释放
	computer1->Dowork();
	delete computer1;
	//开始组装第二台电脑
	cout << "------------------------------------------" << endl;
	cout << "组装第二台intel的电脑" << endl;
	Computer* computer2 = new Computer(new IntelCpu, new IntelVidecard, new LenoveMemory);
	computer2->Dowork();
	delete computer2;
}
int main()
{
	test();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值