多态(虚构的整体,具体的个体)(多态的基本概念/多态的原理剖析/纯虚函数和抽象类/虚析构和纯虚析构)

多态的基本概念

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 多态的基本概念
// 多态分为静态多态和动态多态
// 静态多态: 函数重载还运算符重载属于静态多态,服用函数名
// 动态多态: 派生派和虚函数实现运行时多态


//静态多态和动态多态的区别
// 静态多态的函数地址早绑定-编译阶段确定函数地址
// 动态多态的函数地址晚绑定-运行阶段确定函数地址


// 动态多态满足条件
// 1.有继承关系
// 2.子类重写父类的虚函数
//    重写就是:函数返回值类型 函数名 参数列表 完全相同

// 动态多态的使用
// 父类的指针或引用执行子类对象


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

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

// 执行说话的函数

// C++中允许父子之间的类型转换,不需要强制类型转换
void doSpeak(Animal &animal)
{
	animal.speak();
}

void test01()
{
	Cat c;
	// 属于地址早绑定,在编译阶段确定函数地址
	// 如果想执行让猫说话,那么这个函数地址就不能提前绑定。
	// 需要在运行期间绑定,地址晚绑定
	// 此时用到虚函数的概念,也就是在父类中的函数前加virtual
	// 此作用是让被调用的类的说话函数优先执行,起始也就是加virtual降低了本身的优先级
	// 子类中的virtual可写可不写
	doSpeak(c); // 相当于 Animal &animal = c;
}
void doSpeak(Animal* animal)
{
	animal->speak();
}
void test02()
{
	Cat c;
	doSpeak(&c);
}
int main()
{

	test01();// 引用
	test02();// 指针
	system("pause");
	return 0;
}

多态的原理剖析

此时该类中储存指向该函数的指针

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 多态的原理剖析
class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	};
};
class Cat :public Animal
{
public:
	//重写之后
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};
int main()
{
	cout << "sizeof(Animal) = " << sizeof(Animal) << endl;

	system("pause");
	return 0;
}

多态案例一---- 计算器类

普通写法

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 计算器类普通写法
class Calculate
{
public:

	Calculate(int num1,int num2)
	{
		this->num1 = num1;
		this->num2 = num2;
	}
	int doWork(string operate)
	{
		if (operate == "+")
		{
			return num1 + num2;
		}else if (operate == "-")
		{
			return num1 - num2;
		}else if (operate == "*")
		{
			return num1 * num2;
		}
		// 此种写法如果想增加其它的功能,需要修改源码
		// 在真正的开发中 提倡 开闭原则
		// 开闭原则: 对扩展进行开放,对修改进行关闭
	}
	int num1;
	int num2;
};
// 普通写法
void test01()
{
	Calculate c(10, 20);
	cout << c.num1 << "+" << c.num2 << " = " <<  c.doWork("+") << endl;
	cout << c.num1 << "-" << c.num2 << " = " << c.doWork("-") << endl;
	cout << c.num1 << "*" << c.num2 << " = " << c.doWork("*") << endl;
}
int main()
{
	test01();

	system("pause");
	return 0;
}

多态写法

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// 计算器类-多态写法

// 多态的好处:
// 1.组织结构清晰
// 2.可读性强
// 3.对于前期和后期扩展以及维护性高

// C++开发提倡利用多态设计程序架构,因为多态优点很多
class AbstractCalculate
{
public:
	int num1;
	int num2;
	virtual int calculate()
	{
		return 0;
	}
};
class Add :public AbstractCalculate
{
public:
	virtual int calculate()
	{
		return num1 + num2;
	}
};
class Del :public AbstractCalculate
{
public:
	virtual int calculate()
	{
		return num1 - num2;
	}
};
class Cheng :public AbstractCalculate
{
public:
	virtual int calculate()
	{
		return num1 * num2;
	}
};
void test01()
{
	// 多态使用条件
	// 父类指针或引用指向子类对象

	AbstractCalculate* c = new Add;
	c->num1 = 10;
	c->num2 = 20;
	cout << c->num1 << " + " << c->num2 << " = " << c->calculate() << endl;
	// 用完记得销魂
	delete c;

	c = new Del;
	c->num1 = 10;
	c->num2 = 20;
	cout << c->num1 << " - " << c->num2 << " = " << c->calculate() << endl;
	delete c;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

纯虚函数和抽象类

在多态中,通常父类中虚函数的实现时毫无意义的,主要是调用子类重写的内容

因此可以将虚函数改为纯虚函数

当类中有了纯虚函数,这个类称为抽象类

抽象类特点:

1.无法实例化对象

2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类

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

// 纯虚函数和抽象类
class Animal
{
public:
	// 纯虚函数
	// 只要有一个纯虚函数,这类就称为抽象类
	// 抽象类特点
	// 1.无法实例化对象
	// 2.子类必须重写父类中的纯虚函数,否则无法实例化对象
	virtual void func() = 0;

};
class Cat :public Animal
{
public:
	void func()
	{
		cout << "func函数调用" << endl;
	}

};
void test01()
{
	//Animal a;
	//new Animal;  //抽象类是无法实例化对象的

	Cat c;// 子类必须重写父类中的纯虚函数,否则无法实例化对象
	Animal& animal = c;
	animal.func();
}
int main()
{
	test01();
	system("pause");
	return 0;
}

多态案例二:制作饮品

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
class AbstraceMakeDrinking
{
public:
	// 1.煮水
	virtual void zhuShui() = 0;

	// 2.冲泡
	virtual void chongPao() = 0;

	// 3.倒入杯中
	virtual void daoRuBeiZhong() = 0;

	// 4.加入辅料
	virtual void jiaRuFuLiao() = 0;

	void makeDrink()
	{
		zhuShui();
		chongPao();
		daoRuBeiZhong();
		jiaRuFuLiao();
	}
};
class kaFei :public AbstraceMakeDrinking
{
public:
	// 1.煮水
	virtual void zhuShui()
	{
		cout << "煮咖啡水" << endl;
	}

	// 2.冲泡
	virtual void chongPao()
	{
		cout << "冲泡咖啡" << endl;
	}

	// 3.倒入杯中
	virtual void daoRuBeiZhong()
	{
		cout << "导入咖啡杯中" << endl;
	}

	// 4.加入辅料
	virtual void jiaRuFuLiao()
	{
		cout << "加入咖啡辅料" << endl;
	}
};
void test01()
{
	AbstraceMakeDrinking* coffee = new kaFei;
	coffee->makeDrink();
	delete coffee;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

虚析构和纯虚析构

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
#include<string>
// 虚析构和纯虚析构
// 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时
//无法调用到子类的析构代码
// 因为父类引用指向子类对象,故在释放空间时调用的是父类的析构函数
// 故使用多态(虚析构或纯虚析构)

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

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

// 总结
// 1.虚析构和纯虚析构就是用来解决父类指针释放子类对象
// 2.如果子类中没有堆区数据,可以不写虚析构或纯虚析构
// 3.拥有纯虚析构也属于抽象类
class Animal
{
public:
	// 纯虚析构
	virtual void speak() = 0;
	Animal()
	{
		cout << "Animal类构造函数的调用" << endl;
	}
	 利用虚析构可以解决 父类指针释放子类对象时不干净的问题
	//virtual ~Animal()
	//{
	//	cout << "Animal类析构函数的调用" << endl;
	//}

	// 纯虚析构(需要声明也需要实现)
	// 有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
	virtual ~Animal() = 0;
};
// 子类中需要析构函数释放空间,但是多态走不到子类中的析构函数,
// 所以需要虚析构和纯虚析构
Animal:: ~Animal()
{
	cout << "Animal类析构函数的调用" << endl;
}
class Cat :public Animal
{
public:
	string* name;
	Cat(string name)
	{
		cout << "Cat类构造函数的调用" << endl;
		this->name = new string(name);
	}
	~Cat()
	{
		cout << "Cat类析构函数的调用" << endl;
		if (name != NULL)
		{
			delete name;
			name = NULL;
		}
	}
	virtual void speak()
	{
		cout << *name << "小猫在说话" << endl;
	}
};
void test01()
{
	// 多态:父类指针或引用指向子类对象
	// 引用:给变量取别名
	Animal *animal = new Cat("Tom");
	animal->speak();
	// 父类指针在析构的时候,不回调用子类中析构函数,
	// 导致子类如果有堆区属性,出现内存泄露
	delete animal;
	animal = NULL;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

    // 父类指针在析构的时候,不回调用子类中析构函数,
    // 导致子类如果有堆区属性,出现内存泄露

// 解决方法,将父类析构函数改为虚析构或纯虚析构

多态案例三: 电脑组装

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
// CPU抽象类
class Cpu
{
public:
	virtual void calculate() = 0;
};
// 显卡抽象类
class DisplayCard
{
public:
	virtual void display() = 0;
};
// 内存抽象类
class Memory
{
public:
	virtual void distory() = 0;
};

// 电脑类
class Computer
{
public:

	// 用来接受每一个零件
	Computer(Cpu *cpu, DisplayCard *card, Memory *memory)
	{
		this->cpu = cpu;
		this->card = card;
		this->memory = memory;
	}
	~Computer()
	{
		if (cpu != NULL)
		{
			delete cpu;
			cpu = NULL;
		}
		if (card != NULL)
		{
			delete card;
			card = NULL;
		}
		if (memory != NULL)
		{
			delete memory;
			memory = NULL;
		}
	}

	// 用来协同每一个零件工作
	void work()
	{
		cpu->calculate();
		card->display();
		memory->distory();
	}
private:
	Cpu* cpu;
	DisplayCard* card;
	Memory* memory;
};

// 不同厂商的CPU
class IntelCpu :public Cpu
{
public:
	virtual void calculate()
	{
		cout << "Intel的CPU开始计算了" << endl;
	}
};
class LevoeCpu :public Cpu
{
public:
	virtual void calculate()
	{
		cout << "Levoe的CPU开始计算了" << endl;
	}
};

// 不同厂商的显卡
class IntelDisplayCard :public DisplayCard
{
public:
	virtual void display()
	{
		cout << "Intel的显卡开始显示了" << endl;
	}
};
class LevoeDisplayCard :public DisplayCard
{
public:
	virtual void display()
	{
		cout << "Levoe的显卡开始显示了" << endl;
	}
};

//不同厂商的内存条
class IntelMemory :public Memory
{
public:
	virtual void distory()
	{
		cout << "Intel的内存条开始存储了 " << endl;
	}
};
class LevoeMemory :public Memory
{
public:
	virtual void distory()
	{
		cout << "Levoe的内存条开始存储了 " << endl;
	}
};


void test01()
{
	// 第一台电脑运行
	cout << "第一台电脑运行--------------------------" << endl;
	Cpu* cpu = new IntelCpu;
	DisplayCard* card = new IntelDisplayCard;
	Memory* memory = new IntelMemory;
	Computer *c = new Computer(cpu,card,memory);
	c->work();
	delete c;

	// 第二台电脑运行
	cout << "第二台电脑运行--------------------------" << endl;
	c = new Computer(new LevoeCpu, new LevoeDisplayCard, new LevoeMemory);
	c->work();
	delete c;
	c = NULL;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值