继承与多态(二)

纯虚函数与抽象类

有些时候,我们在设计基类的时候,可能有些函数的函数行为没有办法具体实现,可以不去进行定义,如下,可以声明为纯虚函数

·=0表示这个函数是一个纯虚函数,不需要在该类中实现.

如果一个类里面包含了一个纯虚函数,那么这个函数称为抽象类.抽象类不能实例化对象,但是可以创建基类的引用/指针绑定到派生类对象上.

如果派生类继承抽象类,但是其还没有实现纯虚函数,那么此派生类还是抽象类.

虚函数和构造函数

构造函数函数不可以是虚函数.理由如下:

构造函数的作用:

用来初始化对象,在(构造函数之前)对象只有空间,但是空间里面的数据是未定义的.

虚函数:

·储存在虚函数表里

·虚函数的调用过程:

因为虚函数存储在虚函数表,调用虚函数的时候,需要先访问虚函数表,而虚函数表储存在对象的存储空间中,如果构造函数是虚函数的话,那么按照上述逻辑,调用虚函数就要先访问虚函数表,就要知道对象的空间地址,但是在未调用构造函数情况下,只有空间,而没有对象,也就是不知道空间地址,所以是无法找到虚函数表的,这样也无法调用虚函数了.​​​​​​​

虚函数与析构函数

析构函数可以是虚函数.原因是构造函数已经创建实例化对象,可以访问到虚函数表.

并且,建议析构函数为虚函数.(这样就更加容易实现动态绑定)理由如下:

例:

#include <iostream>
using namespace std;
class Animal
{
public:
     Animal()
     {
         cout<<"调用了基类的构造函数"<<endl;
     }
      ~Animal()//将基类的析构函数不定义为虚函数时
     {
         cout<<"调用了基类的析构函数"<<endl;
     }
};

class dog:public Animal
{
public:
    dog()
    {
        cout<<"调用了子类的构造函数"<<endl;
    }
    ~dog()
    {
        cout<<"调用了子类的析构函数"<<endl;
    }

};


int main()
{
    Animal *c;
    c=new dog();
    delete c;
    return 0;
}

如果不把基类的析构函数定义为虚函数的话,那么最后只会调用的是基类的析构函数,如果子类有自己的新的对象,仅仅调用基类的虚构函数是释放不了子类的对象的(代码不做描述).如果基类定义的析构函数为虚函数,那么(代码不做描述)结果如下:

所以建议析构函数为虚函数.

多重继承

·指从多个基类中产生派生类,多重继承的派生类继承了所有基类的特征和行为.

例:

#include <iostream>
using namespace std;
class Animal
{
public:
    Animal()
    {
        cout<<"调用了基类的构造函数"<<endl;
    }
    virtual ~Animal()
    {
        cout<<"调用了基类的析构函数"<<endl;
    }
};

class dog:public Animal
{
public:
    dog()
    {
        cout<<"狗被构造了"<<endl;
    }
    ~dog()
    {
        cout<<"调用了狗类的析构函数"<<endl;
    }
    virtual void eat()
    {
        cout<<"吃屎"<<endl;
    }
};

class cat:public Animal
{
public:
    cat() {
        cout << "猫被构造了" << endl;
    }

    ~cat() {
        cout << "调用了猫类的析构函数" << endl;
    }

    virtual void eat()
    {
        cout<<"吃鱼"<<endl;
    }

};

class kun:public dog,public cat //继承了猫和狗类
{
public:
    kun() {
        cout << "kun被构造了" << endl;
    }

    ~kun() {
        cout << "调用了kun类的析构函数" << endl;
    }

    virtual void qita()
    {
        cout<<"唱跳rap"<<endl;
    }

};



int main()
{
    kun k;
    k.cat::eat();//k.eat具有二义性,可以选择指定作用域
    return 0;

}

多继承下的类成员作用域

在只有一个基类的情况下,派生类的作用域是嵌套在基类的作用域里面的,名字(函数名,如上)的查找过程名字的查找过程是沿着继承体系自下而上进行的.

派生类的名字会隐藏基类的同名成员.

在多继承的情况下,名字查找过程是在所有直接基类同时进行的,如果查找的名字在多个基类中都可以查到,那么该名字存在访问的二义性.(解决方法如上)

以下是上述代码的构造过程:

派生类可能会多次继承同一个基类,最典型的就是菱形继承.

·即在一个派生类中有两个直接基类,但是这两个基类又继承同一个直接基类,这种情况下就会产生多个副本.

多个副本是没有意义的,建议使用虚继承解决.

虚继承

虚继承就是在一个类上做出声明,例:

class 派生类名称:virtual 继承方式 基类名称

作用:让某一个类做出声明,表示愿意共享他的基类,被共享的基类称为虚基类,不论虚基类在继承体系出现多少次,都只有一个副本.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值