zoukankan      html  css  js  c++  java
  • 虚基类的作用

    (1):当在多条继承路径上有一个公共的基类,在这些路径的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个公共基类说明为虚基类、

      class CBase { };

      class ChildA1:virtual public CBase{ };

      class ChildA2:virtual public CBase{ };

      class ChildB:public ChildA1,ChildA2{ };

      则在类ChildB的对象中,仅有类CBase的一个对象数据

    (2):虚基类的初始化如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类(包括直接派生或间接派生的派生类)中,通过构造函数的初始化表对虚基类进行初始化。例如
    class A//定义基类A
    {
       A(int i){ } //基类构造函数,有一个参数

    };
    class B :virtual public A   //A作为B的虚基类
    {
       B(int n):A(n){ } //B类构造函数,在初始化表中对虚基类初始化
    };
    class C :virtual public A //A作为C的虚基类
    {
       C(int n):A(n){ } 
    //C类构造函数,在初始化表中对虚基类初始化
    };
    class D :public B,public C 
    //类D的构造函数,在初始化表中对所有基类初始化
    {
       D(int n):A(n),B(n),C(n){ }
    };
    注意: 
    在定义类D的构造函数时,与以往使用的方法有所不同。规定: 
    在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。C++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B和类C) 
    对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。

    虚基类的特点:

           (1):虚基类构造函数的参数必须由最新派生出来的类负责初始化(即使不是直接继承).       

       (2)虚基类的构造函数先于非虚基类的构造函数执行。

    下面看一段程序的输出结果:

     1 #include "stdafx.h"
     2 #include<iostream>
     3 using namespace std;
     4 
     5 class CBase{
     6 protected:
     7         int a;
     8 public:
     9     CBase(int na)
    10     {
    11         a = na;
    12         cout << "CBase constructor!" << endl;
    13     }
    14     ~CBase()
    15     {
    16         cout << "CBase deconstructor!" << endl;
    17     }
    18 };
    19 
    20 class ChildA1: virtual public CBase
    21 {
    22 public:
    23     ChildA1(int na):CBase(na)
    24     {
    25         cout << "ChildA1 constructor!" << endl;
    26     }
    27     ~ChildA1()
    28     {
    29         cout << "ChildA1 deconstructor!" << endl;
    30     }
    31     int GetA()
    32     {
    33         return a;
    34     }
    35 };
    36 
    37 class ChildA2 : virtual public CBase
    38 {
    39 public:
    40     ChildA2(int na):CBase(na)
    41     {
    42         cout<< " ChildA2 constructor!" << endl;
    43     }
    44     ~ChildA2()
    45     {
    46         cout<< "ChildA2 deconstructor!" << endl;
    47     }
    48     int GetA()
    49     {
    50         return a;
    51     }
    52 };
    53 
    54 class ChildB:public ChildA1,public ChildA2
    55 {
    56 public:
    57     ChildB(int a1,int a2,int a3):ChildA1(a1),ChildA2(a2),CBase(a3)
    58     {
    59         cout << "ChildB constructor!!" << endl;
    60     }
    61     ~ChildB()
    62     {
    63         cout << "ChildB deconstructor!" << endl;
    64     }
    65 };
    66 
    67 int main()
    68 {
    69     ChildB childb(100,200,300);
    70     //得到从ChildA1继承的值  
    71     cout<<" from ChildA1 : a = "<<childb.ChildA1::GetA();  
    72     //得到从ChildA2继承的值  
    73     cout<<" from ChildA2 : a = "<<childb.ChildA2::GetA()<<endl<<endl;  
    74     return 0;
    75 }

    程序输出的结果:

    从上例中可以看出来,在类ChildB的构造函数初始列表中,调用了间接基类CBase的构造函数,这对于非基类是非法的,但对于虚基类则是合法而且是必要的。

      从输出的结果可以看出来,其公共基类的构造函数只调用了一次,并且优先于非虚基类的构造函数调用,并且发现,子派生类的对象childb的成员变量的值只有一个,所以当公共基类CBase被声明为虚基类,虽然它成为ChildA1和ChildA2的公共基类,但子派生类ChildB中也只有它的一个备份.

  • 相关阅读:
    AD设置PCB等比例打印
    leetcode------Word Search
    leetcode------Subsets II
    leetcode------Subsets
    leetcode------Palindrome Partitioning
    leetcode------Combinations
    leetcode------Binary Tree Zigzag Level Order Traversal
    leetcode------Populating Next Right Pointers in Each Node II
    leetcode------Populating Next Right Pointers in Each Node
    leetcode------Remove Duplicates from Sorted Array II
  • 原文地址:https://www.cnblogs.com/cxq0017/p/6484539.html
Copyright © 2011-2022 走看看