![](https://img.haomeiwen.com/i4264437/4251e03a4812e761.png)
/* 多态分为两类:
* (1)静态多态:函数重载,运算符重载属于静态多态,复用函数名;
* (2)动态多态:派生类和虚函数实现运行时多态。
*
* 静态多态和动态多态区别:
* (1)静态多态的函数地址早绑定 - 编译阶段确定函数地址;
* (2)动态多态的函数地址晚绑定 - 运行阶段确定函数的地址。
*
* 动态多态满足条件:
* (1)满足继承关系;
* (2)子类重写父类虚函数。函数前面加上virtual 关键字变成虚函数, `virtual void func(){}`.
*
* 注:重写,函数名,函数返回类型,参数类型、数量全部相同。需要与重载相区别。
*
* 动态多态使用:父类的【指针或者引用】指向子类对象。`Animal & animal = cat` 或者 `Animal * animal; animal = new Cat`;
*
* 多态的优点:
* (1)代码组织结构;
* (2)可读性强;
* (2)利于前期和后期的扩展以及维护。
*
*
* 在多态中,通常父类中虚函数的实现是毫无意义的,主要是调用子类重写的内容。因此可以将虚函数改为纯虚函数。
* 纯虚函数语法:virtual 返回值类型 函数名 (参数列表) = 0;
* 当类中有了纯虚函数,这个类也称抽象类。
*
* 抽象类特点:
* (1)无法实例化对象;
* (2)子类必须【重写】抽象类中的纯虚函数,否则也属于抽象类,无法实例化。
*
*
* 析构与纯虚析构
* 多态使用时,如果子类中有属性开辟到堆区,由于父类指针在释放时无法调用到子类的析构代码, 因此无法释放子类在堆区开辟的内存。
* 解决方式:将父类中的析构函数改为虚析构或纯虚析构。
*
* 虚析构和纯虚析构共性:
* (1)可以解决父类指针释放子类对象;
* (2)【都需要具体的函数实现】;
* 虚析构和纯虚析构区别:
* (1)如果是纯虚析构,该类属于抽象类,无法实例化对象。
*
*
* 虚析构语法: virtual ~类名(){}
* 纯虚析构语法:virtual ~类名() = 0; // 类内声明
* 类名::~类名(){} // 类外实现.
*
* 小结:
* (1)虚析构和纯虚析构就是用来解决通过父类指针释放子类对象;
* (2)如果子类中没有堆区数据,可以不写虚析构和纯虚析构;
* (3)拥有纯虚析构函数的类也属于抽象类。
*
* 纯虚基类(也即抽象类)不能创建对象,且想要实现多态,则只能创建指针(或引用)指向子类。用new在堆区开辟数据,返回的指针就指向子类。
*/
抽象类中的虚函数指向子类中实现的函数的方式有两种:引用方式和指针方式。
class Base {
public:
virtual void func()=0;
};
class Son: public Base {
public:
void func(){
cout << "I'm your Son." << endl;
}
};
int main(){
// 引用方式
Son son;
Base &a = son;
a.func();
// 指针方式
Base *b = new Son;
b->func();
delete b;
}
多态案例1-计算器类
//
// Created by shexuan on 2021/1/8.
//
#include <iostream>
#include <string>
using namespace std;
class Calculator{
public:
virtual void getResult(int a, int b){
}
};
class Add: public Calculator{
void getResult(int a, int b){
cout << a << " + " << b << " = " << a+b << endl;
}
};
class Sub: public Calculator{
void getResult(int a, int b){
cout << a << " - " << b << " = " << a-b << endl;
}
};
class Multiply: public Calculator{
void getResult(int a, int b){
cout << a << " * " << b << " = " << a*b << endl;
}
};
void test01(){
// 加法, 在堆区开辟新空间,父类虚函数指针指向子类重写的函数
Calculator *calc_add = new Add;
calc_add->getResult(1,2);
delete calc_add;
// 减法, 在堆区开辟新空间,父类虚函数指针指向子类重写的函数
Calculator *calc_sub = new Sub;
calc_sub->getResult(1,2);
delete calc_sub;
// 乘法, 使用引用的方式初始化赋值多态
Multiply mul;
Calculator &calc_mul = mul;
calc_mul.getResult(1,2);
}
void test02(){
Calculator *abc;
// 加法
abc = new Add;
abc->getResult(1,2);
delete abc;
// 减法
abc = new Sub;
abc->getResult(1,2);
// 乘法
Multiply mul;
Calculator &abcc = mul;
abcc.getResult(1,2);
}
int main(){
test01();
test02();
}
多态案例2-组装计算机类
![](https://img.haomeiwen.com/i4264437/c7689a66af44f651.png)
//
// Created by shexuan on 2021/1/9.
//
#include <iostream>
#include <string>
using namespace std;
// 抽象CPU类
class CPU{
public:
virtual void calculate()=0;
};
// 抽象显卡类
class GPU{
public:
virtual void display()=0;
};
// 抽象内存条类
class RAM{
public:
virtual void storage()=0;
};
// 抽象计算机类,将各个配件组合起来
// 不同的组装公司
class Computer{
public:
// 有参构造函数
Computer(CPU * cpu, GPU *gpu, RAM *ram, string brand){
// cout << "m_cpu地址: "<< &m_cpu <<endl;
// cout << "cpu地址: "<< &cpu <<endl;
m_cpu = cpu;
m_gpu = gpu;
m_ram = ram;
m_brand = brand;
}
void doWork(){
cout << "******** 欢迎使用" << m_brand <<"牌电脑 ********" << endl;
// CPU 工作
m_cpu->calculate();
// GPU 工作
m_gpu->display();
// 内存条工作
m_ram->storage();
cout << "******** 已关机! ********" << endl;
}
// 析构函数
~Computer(){
if (m_cpu!=NULL){
delete m_cpu;
m_cpu=NULL;
}
if (m_gpu!=NULL){
delete m_cpu;
m_gpu=NULL;
}
if (m_ram!=NULL){
delete m_cpu;
m_ram=NULL;
}
}
string m_brand;
CPU *m_cpu; // 使用抽象类声明,具体实例化时抽象类虚函数指针会指向子类具体实现的函数
GPU *m_gpu;
RAM *m_ram;
};
// 不同品牌的配件, 继承自上面的抽象配件类
class IntelCPU: public CPU {
public:
void calculate(){
cout << ">>> >>> Intel CPU开始计算 ... ..." << endl;
}
};
class AmdCPU: public CPU{
public:
void calculate(){
cout << ">>> >>> AMD CPU开始计算 ... ..." << endl;
}
};
class NvdGPU: public GPU{
void display(){
cout << ">>> >>> 英伟达GPU开始显示 ... ..." << endl;
}
};
class AmdGPU:public GPU{
void display(){
cout << ">>> >>> AMD GPU开始显示 ... ..." << endl;
}
};
class JsdRAM:public RAM{
void storage(){
cout << ">>> >>> 金士顿内存条开始存储 ... ... " << endl;
}
};
class SsgRAM: public RAM{
void storage(){
cout << ">>> >>> 三星内存条开始储存 ... ... " << endl;
}
};
// 上面的定义完毕,下面开始组装电脑
void testt01(){
CPU * cpu;
GPU * gpu;
RAM * ram;
// 组装联想电脑
cpu = new IntelCPU(); // IntelCPU无参构造实例化
gpu = new NvdGPU();
ram = new JsdRAM();
string brand = "联想";
Computer lenovo(cpu, gpu, ram, brand);
lenovo.doWork();
cout << "CPU 地址:" << &cpu << endl;
cout << "联想CPU地址:" << &lenovo.m_cpu << endl; // 两者地址不同,说明联想新建了个地址来存放CPU对象
// delete cpu; // 若Computer没有构建析构函数,则需要在这里把所有零件一个一个delete掉
// delete gpu;
// delete ram;
// 组装神舟电脑
cpu = new AmdCPU; // AmdCPU 无参构造实例化
gpu = new AmdGPU;
ram = new SsgRAM;
string brand2 = "神舟";
Computer zhanshen(cpu, gpu, ram, brand2); //神舟战神
zhanshen.doWork();
// delete cpu;
// delete gpu;
// delete ram;
}
int main(){
testt01();
}
网友评论