美文网首页
黑马C++视频笔记《多态》

黑马C++视频笔记《多态》

作者: 井底蛙蛙呱呱呱 | 来源:发表于2021-01-09 15:26 被阅读0次
抽象父类虚函数是如何指向子类的
/* 多态分为两类:
 *  (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-组装计算机类

//
// 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();
}

相关文章

网友评论

      本文标题:黑马C++视频笔记《多态》

      本文链接:https://www.haomeiwen.com/subject/yqmcaktx.html