虚基类 虚函数 纯虚函数

虚基类

class A
{
public:
    int iValue;
};

class B :public A
{
public:
    void bPrintf() { cout << "This is class B" << endl; };
};

class C :public A
{
public:
    void cPrintf() { cout << "This is class C" << endl; };
};

class D :public B, public C
{
public:
    D() {};
    void dPrintf() { cout << "This is class D" << endl; };
};

void main()
{
    D d;
    //cout << d.iValue << endl; //错误,不明确的访问
    cout << d.A::iValue << endl; //正确
    cout << d.B::iValue << endl; //正确
    cout << d.C::iValue << endl; //正确
}

类B,C继承A,类D又继承B和C,这时对于D中的变量iValue就有多继承路径,可以是B继承过来的,也可是C中继承过来的,所以引用时必须加作用域。为了验证这个事实,分别对A,B,C,D求sizeof,得到4,4,4,8,这说明类D的内存中保存了两个iValue变量,而不是1个。C++引入虚基类来消除这种菱形继承中出现的重复继承基类变量的情况。

class A
{
public:
    int iValue;
};

class B :virtual public A
{
public:
    void bPrintf() { cout << "This is class B" << endl; };
};

class C :virtual public A
{
public:
    void cPrintf() { cout << "This is class C" << endl; };
};

class D :public B, public C
{
public:
    D() { iValue = 0; };
    void dPrintf() { cout << "This is class D" << endl; };
};

void main()
{
    D d;
    cout << d.iValue<<endl;
    cout << sizeof(A) << sizeof(B) << sizeof(C) << sizeof(D) << endl;
}

output: 0
        48812

引入虚基类之后,只影响菱形继承的类D,对B,C没有使用的影响,只是在它们的存储中加入了类似于虚函数列表的功能,用来防止重复存储来自与基类的成员。

虚函数

多态性可分为两类:静态多态和动态多态。函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的。

每个含有虚函数的类有一张虚函数表(vtbl),表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。

没有虚函数的C++类,是不会有虚函数表的。

两张图:

这里写图片描述

在基类的成员函数前加virtual关键字表示这个函数是一个虚函数,所谓虚函数就是在编译的时候不确定要调用哪个函数,而是动态决定将要调 用哪个函数,要实现虚函数必须派生类的函数名与基类相同,参数名参数类型等也要与基类相同。但派生类中的virtual关键字可以省略,也表 示这是一个虚函数。下面来解决一下代码,声明一个基类的指针(必须是基类,反之则不行)p,把p指向类A的实例a,调用funPrint函数,这 时系统会判断p所指向的实例的类型,如果是A类的实例就调用A类的funPrint函数,如果是B类的实例就调用B类的funPrint函数。

纯虚函数

与其叫纯虚函数还不如叫抽象类,它只是声明一个函数但不实现它,让派生类去实现它,其实这也很好理解。


总结

虚基类 
1, 一个类可以在一个类族中既被用作虚基类,也被用作非虚基类。 
2, 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的子对象。 
3, 虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。 
4, 最派生类是指在继承结构中建立对象时所指定的类。 
5, 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。 
6, 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生 类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象 只初始化一次。 
7, 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。 

虚函数 
1, 虚函数是非静态的、非内联的成员函数,而不能是友元函数,但虚函数可以在另一个类中被声明为友元函数。 
2, 虚函数声明只能出现在类定义的函数原型声明中,而不能在成员函数的函数体实现的时候声明。 
3, 一个虚函数无论被公有继承多少次,它仍然保持其虚函数的特性。 
4, 若类中一个成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时 ,对该成员函数调用可采用动态联编。 
5, 定义了虚函数后,程序中声明的指向基类的指针就可以指向其派生类。在执行过程中,该函数可以不断改变它所指向的对象,调用不同 版本的成员函数,而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。 纯虚函数 版本的成员函数,而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。

纯虚函数 
1, 当在基类中不能为虚函数给出一个有意义的实现时,可以将其声明为纯虚函数,其实现留待派生类完成。 
2, 纯虚函数的作用是为派生类提供一个一致的接口。 
3, 纯虚函数不能实化化,但可以声明指针。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值