多态

多态的基本概念

首先多态分为静态多态和动态多态

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名

  • 动态多态: 派生类和虚函数实现运行时多态静态多态和动态多态区别:

    • 静态多态的函数地址早绑定 - 编译阶段确定函数地址

    • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

在这个案例中,

class animal
{
public:
    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 &a)
{
    a.speak();
}


void test()
{
    cat c;
    dospeak(c);
    dog g;
    dospeak(g);
}

我们只需要改动一行,那么输出就正确了

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

在函数面前加入virtual,那么这个函数就变成虚函数了。 那么比那一起在编译的时候就不能确定函数调用,要到运行的时候才知道

多态的满足条件

1,有继承关系 2 子类重写父类中的虚函数

多态使用:父类指针或引用指向子类对象

案例一

其实这个案例就可以发现,父类中的虚函数根本没有调用过

父类指针指向子类对象,所以我们是caculator *p;

class caculator
{
public:
    virtual int getanswe()
    {
        return 0;
    }
    int a;
    int b;
};
class add :public caculator
{
public:
    int getanswe()
    {
        return a+b;
    }
};

class sub :public caculator
{
public:
    int getanswe()
    {
        return a-b;
    }
};
class mul :public caculator
{
public:
    int getanswe()
    {
        return a*b;
    }
};


void test()
{
    caculator *p1=new add;
    p1->a=10;
    p1->b=10;
    cout<<p1->getanswe()<<endl;
    delete p1;
    p1=new sub;
    p1->a=10;
    p1->b=10;
    cout<<p1->getanswe()<<endl;
    delete p1;
    p1=new mul;
    p1->a=10;
    p1->b=10;
    cout<<p1->getanswe()<<endl;
    delete p1;
}

纯虚函数与抽象类

这里先了解概念?

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

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

纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;

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

无法实例化对象 这个意思是例如 animal a;这个就是不合法的

子类函数必须重写纯虚函数,不然子类也是抽象类。

class base
{
public:
    virtual void func()=0;
};

class son:public base
{
    void func()
    {
        cout<<"func调用"<<endl;
    }
};


void test()
{
   base *base=NULL;
   base=new son;
   base->func();
   delete base;
}

如果写这个就会报错,因为无法实例化对象。

案例二

class base
{
public:
    virtual void boil()=0;
    virtual void brew()=0;
    virtual void pour()=0;
    virtual void add()=0;
    void dosome()
    {
        boil();brew();pour();add();
    }
};

class coffee:public base
{
    void boil()
    {
        cout<<"煮农夫山泉"<<endl;
    }
    void brew()
    {
        cout<<"冲泡咖啡"<<endl;
    }
    void pour()
    {
        cout<<"倒入咖啡杯"<<endl;
    }
    void add()
    {
        cout<<"加入牛奶和咖啡"<<endl;
    }

};
class tea:public base
{
    void boil()
    {
        cout<<"煮山泉水"<<endl;
    }
    void brew()
    {
        cout<<"冲泡茶叶"<<endl;
    }
    void pour()
    {
        cout<<"倒入茶杯"<<endl;
    }
    void add()
    {
        cout<<"加入柠檬"<<endl;
    }

};

void test()
{
  base *b=NULL;
  b=new coffee;
  b->dosome();
  cout<<"-------------------------------------"<<endl;
  delete b;
  b=new tea;
  b->dosome();
  delete b;
}

虚析构与纯虚析构

可以看到这里结果都没有走到cat的析构函数。因为这里发生了多态,我们使用的是父类animal的指针去指向子类对象。代码正常运行是要test函数跑完再进行析构。结果我们已经delete animal这个指针了

父类指针在析构的时候不会去调用子类的析构

class animal
{
public:
    animal()
    {
        cout<<"animal构造函数"<<endl;
    }
    virtual  void speak()=0;
~animal()
{
    cout<<"animal析构函数"<<endl;
}
};

class cat:public animal
{
public:
    cat(string name)
    {
        cout<<"cat构造函数"<<endl;
        m_name=new string(name);
    }
    virtual void speak()
    {
        cout<<"小猫在说话"<<endl;
    }
    ~cat()
    {
        if(m_name!=NULL)
        {
            delete m_name;
            m_name=NULL;
        }
        cout<<"cat析构函数"<<endl;
    }
    string *m_name;
};

void test()
{
    animal *an=new cat("617");
    an->speak();

    delete an;

}

如果将父类中的析构函数改为虚析构,OK了

virtual ~animal()
{
    cout<<"animal析构函数"<<endl;
}

纯虚析构

纯虚析构和纯虚函数一样的写法 但是和纯虚函数一样一定要加上实现,纯虚函数实在子类实现,纯虚析构是在类外实现,虚析构也要写代码实现。

因为析构函数你只要写了那就会走你写的这个,所以一定要写代码。

有了纯虚析构之后,这个类也属于抽象类,无法实例化

virtual ~animal()=0;
animal::~animal()
{
cout<<"animal析构函数"<<endl;
}

案例三

代码运行逻辑: 首先是要组装一台电脑,一台电脑有三个零件:内存条,CPU,GPU;这里我们将电脑运行了什么CPU,GPU,内存条写在电脑这个类中,只需要传入什么牌子的让他自己输出就好。
第二,定义了CPU,GPU,内存条这三个类,里面只有纯虚函数,这是抽象基类,让他们的各个品牌的子类去实现具体函数。各个品牌的子类先继承了父类;

class CPU
{
public:
    virtual void caculate()=0;
};
class GPU
{
public:
    virtual void show()=0;
};
class memory
{
public:
    virtual void storage()=0;
};


class computer
{
public:
    computer(CPU *cpu,GPU *gpu,memory *mm)
    {
        m_cpu=cpu;
        m_gpu=gpu;
        m=mm;
    }

    void work()
    {
        m_cpu->caculate();
        m_gpu->show();
        m->storage();
    }
    ~computer()
    {
        if(m_cpu!=NULL)
        {
            delete m_cpu;
            m_cpu=NULL;
        }
        if(m_gpu!=NULL)
        {
            delete m_gpu;
            m_gpu=NULL;
        }
        if(m!=NULL)
        {
            delete m;
            m=NULL;
        }
    }
private:
    CPU* m_cpu;
    GPU* m_gpu;
    memory *m;
};

class InterCPU: public CPU
{
public:
    void  caculate()
    {
        cout<<"InterCPU正在计算"<<endl;
    }

};
class InterGPU:public GPU
{
public:
    void show()
    {
        cout<<"InterGPU正在显示"<<endl;
    }
};
class AMDCPU:public CPU
{
public:
    void  caculate()
    {
        cout<<"AMDCPU正在计算"<<endl;
    }
};
class AMDGPU:public GPU
{
public:
    void show()
    {
        cout<<"AMDGPU正在显示"<<endl;
    }
};
class ACER:public memory
{
public:
    void storage()
    {
        cout<<"ACER内存条正在储存"<<endl;
    }
};
class Lenovo:public memory
{
public:
    void storage()
    {
        cout<<"Lenovo内存条正在储存"<<endl;
    }
};

void test()
{
   CPU *Intercpu=new InterCPU;
   GPU* Intergpu=new InterGPU;
   memory* acer=new ACER;
   cout<<"第一台电脑正在工作"<<endl;
   computer *c1=new computer(Intercpu,Intergpu,acer);
   c1->work();
   delete c1;
   cout<<"--------------------------"<<endl;
    cout<<"第二台电脑正在工作"<<endl;
    computer *c2=new computer(new AMDCPU,new AMDGPU,new ACER);
    c2->work();
    delete c2;
    cout<<"--------------------------"<<endl;
    cout<<"第三台电脑正在工作"<<endl;
    computer *c3=new computer(new AMDCPU,new InterGPU,new Lenovo);
    c3->work();
    delete c3;
}