C++学习笔记:多态

C++学习笔记:多态

  • 1.多态基本概念
    • 1.1.静态多态
    • 1.2.动态多态
  • 2.纯虚函数与抽象类
  • 3.虚析构与纯虚析构
    • 3.1虚析构
    • 3.2纯虚析构
  • 4.综合案例
  • 总结

C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数,多态分为静态多态与动态多态。
多态使用条件:父类指针或引用指向子类


1.多态基本概念

1.1.静态多态

静态多态:函数重载和运算符重载等复用函数名为静态多态

1.2.动态多态

动态多态:派生类和虚函数实现运行时多态,需要在子类中对父类的虚函数进行重写
虚函数: virtual +函数

//父类引用指向子类
#include  
using namespace std;
class Animal
{
public:
    virtual void speak()
    {
        cout << "动物在说话" << endl;
    }
};
class Cat :public Animal
{
public:
    void speak()
    {
        cout << "小猫在说话" << endl;
    }
};
class Dog :public Animal
{
public:
    void speak()
    {
        cout << "小狗在说话" << endl;
    }
};
void dospeak(Animal& animal)//Animal & animal = cat;父类指针可以指向子类
{
    animal.speak();
}
void test01()
{
    Cat cat;
    dospeak(cat);
    Dog dog;
    dospeak(dog);
}
int main()
{
    test01();
    return 0;
}

在不同类的对象调用dospeak函数时实现了不同的功能。

//父类指针指向子类
#include  
using namespace std;
class Animal
{
public:
    virtual void speak()
    {
        cout << "动物在说话" << endl;
    }
};
class Cat :public Animal
{
public:
    void speak()
    {
        cout << "小猫在说话" << endl;
    }
};
class Dog :public Animal
{
public:
    void speak()
    {
        cout << "小狗在说话" << endl;
    }
};

void test01()
{
    Animal* ptr = new Cat;
    ptr->speak();
    delete ptr;
    Dog dog;
    ptr = new Dog;
    ptr->speak();
    delete ptr;

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

2.纯虚函数与抽象类

纯虚函数:没有函数体,同时在定义的时候,其函数名后面要加上“= 0”。
语法:virtual 返回值类型 函数名(参数列表) = 0;

virtual void speak() = 0;

抽象类:类中有了纯虚函数,则为抽象类。
抽象类无法实例化对象,子类必须重写父类中的纯虚函数不然也视为抽象类。

Animal a;//不允许使用抽象类实例化对象

3.虚析构与纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用子类的析构函数。
解决:将父类中的析构函数改为虚析构或者纯虚析构
虚析构语法:virtual ~类名() {};
纯虚析构语法:virtual ~类名() = 0;
添加纯虚析构后,父类也变为抽象类,不可实例化对象。
但是虚析构与纯虚析构函数不仅要声明,也需要实现
虚析构与纯虚析构不共存

// 父类指针指向子类
#include  
#include  
using namespace std;
class Animal
{
public:
    Animal()
    {
        cout << "Animal构造函数调用" << endl;
    }

    virtual void speak() = 0;
    //虚析构解决 父类指针释放子类对象不干净的问题
    ~Animal()
    {
        cout << "Animal析构函数调用" << endl;
    }
    //纯虚析构
    //virtual ~Animal() = 0;
};
//Animal::~Animal()
//{
//    cout << "Animal纯虚析构调用" << endl;
//}
class Cat :public Animal
{
public:
    Cat(string name)
    {
        cout << "Cat构造函数调用" << endl;
        m_name = new string (name);
    }

    void speak()
    {
        cout <<*m_name<< "小猫在说话" << endl;
    }

    string* m_name;
    
    ~Cat()
    {
        cout << "Cat析构函数调用" << endl;
        if (m_name != NULL)
        {
            delete m_name;
            m_name = NULL;
        }
    }

};

void test01()
{
    //Animal a;不允许使用抽象类实例化对象
    Animal* ptr = new Cat("Ton");
    ptr->speak();
    delete ptr;
}
int main()
{
    test01();
    return 0;
}

输出为:
Animal构造函数调用
Cat构造函数调用
Ton小猫在说话
Animal纯虚析构调用

此时程序并未调用子类的析构函数,存在父类指针释放子类对象不干净的问题,采用虚析构或者纯虚析构的方式对子类对象进行释放。

3.1虚析构

将普通的析构函数改成虚析构函数

    //虚析构解决 父类指针释放子类对象不干净的问题
    virtual ~Animal()
    {
        cout << "Animal析构函数调用" << endl;
    }

此时的输出为:
Animal构造函数调用
Cat构造函数调用
Ton小猫在说话
Cat析构函数调用
Animal析构函数调用

可见子类对象的析构函数被调用

3.2纯虚析构

用纯虚析构时要函数体不可为空,需要在类外对函数体内容进行丰富,补充以下代码:

    //纯虚析构
    virtual ~Animal() = 0;

类外:

Animal::~Animal()
{
    cout << "Animal纯虚析构调用" << endl;
}

此时的输出为:
Animal构造函数调用
Cat构造函数调用
Ton小猫在说话
Cat析构函数调用
Animal纯虚析构调用

4.综合案例

描述:用多态的方式实现对电脑的组装,电脑类中是各种部件的指针用于对部件的访问。

// 父类指针指向子类
#include  
#include  
using namespace std;

class GPU
{
public:
    virtual void GPUwork()
    {
    };//虚函数
};
class IntelGPU:public GPU
{
    void GPUwork()//重写父类中的虚函数
    {
        cout << "IntelGPU已配置" << endl;
    }
};
class LenovoGPU:public GPU
{
    void GPUwork()//重写父类中的虚函数
    {
        cout << "LenovoGPU已配置" << endl;
    }
};

class Memory
{
public:
    virtual void Memorywork()= 0;//纯虚函数
};
class IntelMemory :public Memory
{
    void Memorywork()//重写父类中的虚函数
    {
        cout << "IntelMemory已配置" << endl;
    }
};
class LenovoMemory :public Memory
{
    void Memorywork()//重写父类中的虚函数
    {
        cout << "LenovoMemory已配置" << endl;
    }
};
class Computer
{
public:
    Computer(Memory* memory,GPU* gpu)
    {
        m_memory = memory;
        m_gpu = gpu;
    }
    Memory* m_memory;
    GPU* m_gpu;

    void assemble()
    {
        this->m_gpu->GPUwork();
        this->m_memory->Memorywork();
    }
    ~Computer()//析构函数释放部件指针所指的空间
    {
        if (m_gpu != NULL)
        {
            delete m_gpu;
            m_gpu = NULL;
        }
        if (m_memory != NULL)
        {
            delete m_memory;
            m_memory = NULL;
        }
    }
};

void test01()
{
    Memory* memory = new IntelMemory;//父类指针指向子类
    GPU* gpu = new IntelGPU;//父类指针指向子类
    cout << "第一台电脑已经装配" << endl;
    Computer* ptr = new Computer(memory, gpu);//初始化一个Computer类指针变量
    ptr->assemble();
    delete ptr;

    Computer* ptr1 = new Computer((new IntelMemory), (new LenovoGPU));
    cout << "第二台电脑已经装配" << endl;
    ptr1->assemble();
    delete ptr1;
};
int main()
{
    test01();
    return 0;
}

总结

多态的写法在查找错误时可以只查看出问题的代码

你可能感兴趣的:(C++)