赞
踩
4月1日
一、多态
1、多态分为两类:静态多态、动态多态
静态多态:函数的重载和运算符的重载属于静态多态,复用函数名
动态多态:派生类和虚函数运行时实现多态
区别:
静态多态的函数地址早绑定,编译阶段确定函数地址
动态多态的函数地址晚绑定,运行阶段确定函数地址
2、函数重写:函数返回值类型、函数名、参数列表完全相同
3、动态多态满足条件:
1)有继承关系
2)子类重写父类的虚函数
4、动态多态的使用
父类的指针或者引用指向子类的对象
5、多态案例—计算机类
1)多态的优点
代码组织清晰
可读性强
利于后期的扩展以及维护
2)案例
传统写法:
传统写法:如果想扩展新功能,需要修改源码,在真实的开发中,提倡开闭原则:对扩展进行开发,对修改进行关闭
多态写法:
代码:
- #include<iostream>
-
- using namespace std;
-
-
- //利用多态实现计算器
-
- //实现计算器抽象类
-
- class AbstractCalculator{
-
- public:
-
- int m_num1;
-
- int m_num2;
-
- //设为虚函数
-
- virtual int getResult()
-
- {
-
- return 0;
-
- }
-
- };
-
-
-
- //加法计算器类
-
- class AddCalculator:public AbstractCalculator {
-
- public:
-
- int getResult()
-
- {
-
- return AbstractCalculator::m_num1 +AbstractCalculator::m_num2;
-
- }
-
- int m_num1; //若此处再声明成员变量,则会造成此类的成员将父类的覆盖掉相加,而不能实现多态,或者加作用域也可以也可以
-
- int m_num2;
-
- };
-
-
-
- //减法计算器类
-
- class SubCalculator :public AbstractCalculator {
-
- public:
-
- int getResult()
-
- {
-
- return m_num1 - m_num2;
-
- }
-
-
-
- };
-
- //乘法计算器类
-
- class MulCalculator :public AbstractCalculator {
-
- public:
-
- int getResult()
-
- {
-
- return m_num1 * m_num2;
-
- }
-
-
-
- };
-
- //除法计算器类
-
- class ChuCalculator :public AbstractCalculator {
-
- public:
-
- int getResult()
-
- {
-
- return m_num1 / m_num2;
-
- }
-
-
-
- };
-
-
-
- void test02()
-
- {
-
- //多态使用方法:父类的指针或引用指向子类对象
-
- AbstractCalculator *abc = new AddCalculator;
-
- abc->m_num1 = 10;
-
- abc->m_num2 = 5;
-
- cout << abc->m_num1 << "+" << abc->m_num2 << "=" << abc->getResult() << endl; //注意子类中不能再重新声明m_num1,m_num2,否则会造成出错
-
- //对象用完后,记得销毁,因为其置于堆区:需手动销毁
-
- delete abc;
-
- abc = new SubCalculator;
-
- abc->m_num1 = 20;
-
- abc->m_num2 = 15;
-
- cout << abc->m_num1 << "-" << abc->m_num2 << "=" << abc->getResult() << endl;
-
- delete abc;
-
-
-
- abc = new MulCalculator;
-
- abc->m_num1 = 10;
-
- abc->m_num2 = 15;
-
- cout << abc->m_num1 << "*" << abc->m_num2 << "=" << abc->getResult() << endl;
-
- delete abc;
-
- abc = new ChuCalculator;
-
- abc->m_num1 = 200;
-
- abc->m_num2 = 2;
-
- cout << abc->m_num1 << "/" << abc->m_num2 << "=" << abc->getResult() << endl;
-
- delete abc;
-
-
-
- }
-
-
- int main()
-
- {
-
- test02();
-
- return 0;
-
- }
6、纯虚函数和抽象类
在多态中,通常父类中的虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将其改为纯虚函数。
1)语法 virtual 返回值类型 函数名(参数列表)=0;
当类中有了纯虚函数,这个类也称为抽象类
2)抽象类的特点:
无法实例化对象;子类必须重写抽象类中的纯虚函数,否则也属于抽象类;
7、虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方法:将父类中的析构函数改为虚析构和纯虚析构
1)虚析构和纯虚析构的共性:
可以解决父类指针释放子类对象、都需要具体的函数实现
2)区别
如果是纯虚析构,该类属于抽象类,无法实例化对象
3)示例
常规不写虚析构的写法
- #include<iostream>
-
- using namespace std;
-
- #include<string>
-
-
-
- class Drink{
-
- public:
-
- int m_num1;
-
- int m_num2;
-
- Drink()
-
- {
-
- cout << "Drink的构造函数调用" << endl;
-
- }
-
- //纯虚函数 此时类为抽象类
-
- virtual void zhuWater() = 0;
-
- void makeDrink()
-
- {
-
- zhuWater();
-
- }
-
- ~Drink()
-
- {
-
- cout << "Drink的析构函数调用" << endl;
-
- }
-
- };
-
-
-
- //子类
-
- class Tea:public Drink {
-
- public:
-
- Tea(string name)
-
- {
-
- cout << "Tea构造函数" << endl;
-
- m_Name = new string(name);
-
- }
-
- virtual void zhuWater()
-
- {
-
- cout<<*m_Name << "煮水" << endl; //注意指针加*解引用
-
- }
-
- ~Tea()
-
- {
-
- if (m_Name != NULL)
-
- {
-
- cout << "Tea的析构函数调用" << endl;
-
- delete m_Name;
-
- m_Name = NULL;
-
- }
-
- }
-
- string *m_Name;
-
-
-
- };
-
-
-
-
-
- void test02()
-
- {
-
- Drink *a = new Tea("龙井");
-
- a->makeDrink();
-
- delete a;
-
- }
-
-
-
- int main()
-
- {
-
- test02();
-
- return 0;
-
- }
结果:
可以看出并没有调用子类的析构来销毁在堆区建的属性数据。堆区数据没有释放干净会导致内存泄漏。
用虚析构解决:
纯虚析构(需要声明又需要有实现):
有了纯虚析构之后这个类也属于抽象类,无法实例化;
不是每个类都需要写虚析构或者纯虚析构,它们都是为了解决多态时,在子类堆区创建了数据,父类无法调用子类析构代码来释放堆区数据造成内存泄漏的问题。若子类堆区无数据,则可以不写它们。
8、案例:电脑组装
一台电脑分为CPU、内存条、显卡 分别写为三个抽象基类 并提供其功能的纯虚函数作为后续调用接口;
然后写不同的厂商类(生产不同的CPU、显卡、内存条),并实现其纯虚函数;
然后创建一个电脑类提供让电脑工作的函数,并且调用每个零件工作的接口;
即用不同厂商的零件去组装它,并使它工作;
代码:
- #include<iostream>
- #include<string>
- using namespace std;
- //cpu类
- class CPU {
- //注意若不写明其访问权限 则默认为私有,类外不可访问
- public:
- //纯虚函数 计算
- virtual void calculate() = 0;
- };
-
- //显卡类
- class VideoCard {
- public:
- //纯虚函数 显示
- virtual void display() = 0;
- };
-
- //内存条类
- class StoreTiao {
- public:
- //纯虚函数 存储
- virtual void store() = 0;
- };
-
- //电脑类 提供工作的函数
- class Computer {
- public:
- //构造函数 传入详细零件指针
- Computer(CPU *cpu, VideoCard *videoCard, StoreTiao *memory)
- {
- m_cpu = cpu;
- m_videoCard = videoCard;
- m_memory = memory;
- }
-
- //让零件工作起来 调用其接口
- void doWork()
- {
- m_cpu->calculate();
- m_videoCard->display();
- m_memory->store();
- }
- //提供电脑析构函数 释放3个电脑零件
- ~Computer()
- {
- if (m_cpu != NULL)
- {
- delete m_cpu;
- m_cpu = NULL;
- }
- if (m_videoCard != NULL)
- {
- delete m_videoCard;
- m_videoCard = NULL;
- }
- if (m_memory != NULL)
- {
- delete m_memory;
- m_memory = NULL;
- }
- cout << "析构函数将零件内存释放完毕" << endl;
- }
- private:
- CPU *m_cpu;
- VideoCard *m_videoCard;
- StoreTiao *m_memory;
- };
-
- //具体厂商
- //戴尔
- class DelMemory : public StoreTiao {
- public:
- virtual void store()
- {
- cout << "戴尔内存条开始工作 存储" << endl;
- }
- };
-
- class DelCPU :public CPU {
- public:
- virtual void calculate()
- {
- cout << "戴尔CPU开始工作 计算" << endl;
- }
- };
-
- class DelVideoCard : public VideoCard{
- public:
- virtual void display()
- {
- cout << "戴尔显卡开始工作 显示" << endl;
- }
-
- };
-
- //Lenovo
- class LenovoMemory : public StoreTiao {
- public:
- virtual void store()
- {
- cout << "联想内存条开始工作 存储" << endl;
- }
- };
-
- class LenovoCPU :public CPU {
- public:
- virtual void calculate()
- {
- cout << "联想CPU开始工作 计算" << endl;
- }
- };
-
- class LenovoVideoCard : public VideoCard {
- public:
- virtual void display()
- {
- cout << "联想显卡开始工作 显示" << endl;
- }
- };
-
-
- //Intel
- class IntelMemory : public StoreTiao {
- public:
- virtual void store()
- {
- cout << "因特尔内存条开始工作 存储" << endl;
- }
- };
-
- class IntelCPU :public CPU {
- public:
- virtual void calculate()
- {
- cout << "因特尔CPU开始工作 计算" << endl;
- }
- };
-
- class IntelVideoCard : public VideoCard {
- public:
- virtual void display()
- {
- cout << "因特尔显卡开始工作 显示" << endl;
- }
-
- };
-
- void test01()
- {
- //第一台电脑零件
- //数据存放在堆区 需手动释放
- CPU *intelCpu = new IntelCPU;
- VideoCard *delVideoCard = new DelVideoCard;
- StoreTiao *lenovoMemore = new LenovoMemory;
- //创建第一台电脑
- //Computer computer1(intelCpu, delVideoCard, lenovoMemore);//第一种创建 放在栈区
- Computer *computer1 = new Computer(intelCpu, delVideoCard, lenovoMemore);//第二种创建 放在堆区 需手动释放
- computer1->doWork();
- delete computer1;
- }
-
- int main()
- {
- test01();
- return 0;
- }
-
注意释放内存!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。