zoukankan      html  css  js  c++  java
  • 转载 C++中虚继承防止二义性

    原文地址http://patmusing.blog.163.com/blog/static/135834960201032527733/

    虚继承,就是在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类,如下面代码中的base类。虚继承在多重继承的时可以防止二义性。

        class base;

        class derived1 : virutal public base;

        class derived2 : virtual public base;

        class derived3 : public derived1, public derived2;

    以上的代码如果用到了base中的某个成员变量就不会产生二义性。和#progma once在头文件中的作用类似。请看下面的例子:

    #include <iostream>

    using namespace std;

     

    class Parent

    {

    public:

          int p;                                       // p将会被所有的子类继承,也将是二义性的根源

     

          inline Parent()

          {

                   p = 10;

          }

    };

     

    class Child1 : public Parent

    {

    public:

          int c1;

     

          inline Child1()

          {

                   p = 12;                           // p在子类Child1中被赋值为

                   c1 = 12;

          }

    };

     

    class Child2 : public Parent

    {

    public:

          int c2;

     

          inline Child2()

          {

                   p = 13;                          // p在子类Child2中被赋值为

                   c2 = 13;

          }

    };

     

    class GrandChild : public Child1, public Child2

    {

    public:

          int grandchild;

     

          // p显然也存在于GrandChild中,但是到底是,还是呢?这就产生了二义性

          inline GrandChild()

          {

                   grandchild = 14;

          }

    };

     

    int main(void)

    {

          GrandChild* pGC = new GrandChild();

     

          cout << pGC->p << endl;

     

          return 0;

    }

    上面程序是不能通过编译的,编译器输出的错误信息如下:

    …: error C2385: 'GrandChild::p' is ambiguous

    …: warning C4385: could be the 'p' in base 'Parent' of base 'Child1' of class 'GrandChild'

    …: warning C4385: or the 'p' in base 'Parent' of base 'Child2' of class 'GrandChild'

    正如编译器告诉我们的那样,GrandChild::p是模棱两可,它被Child1继承了即Child1中包含了一个Parent subobject,也被Child2继承了即Child2中也包含了一个Parent suboject,然后GrandChild又同时继承了Child1和Child2,根据“derived class中要保持base class的完整原样性原则”,因此GrandChild包含了两个ParentObject。所以当pGC->p时,编译器根本无法确定是调用Child1::p还是Child2::p,由此边产生了模棱两可的情形。怎么解决这样的问题呢?答案就是用虚继承或者叫虚基类的方式。

    在上面的示例程序中做如下改动:

    class Child1 : public Parent      ->      class Child1 : virtual public Parent

    class Child2 : public Parent      ->      class Child2 : virtual public Parent

    GrandChild的定义维持不变:

    class GrandChild : public Child1, public Child2

    做了上述改动后,即增加了两个virtual关键字,再编译就不会出现ambiguous之类的错误了。这是因为加上了virtual关键字后,就可以保证Parent suboject在GrandChild中只存在一份,从而消除了ambiguity。上面修改后的程序运行结果是13,这说明Child2类的那个p起了作用,如果GrandChild的定义写成:

    class GrandChild : public Child2, public Child1

    那么运行结果将是12。

    上面的试验结果表面,在多重继承的时候,如果父类中有同名的成员变量(类似这篇文章中谈及的例子),为了防止二义性,一般要采用虚继承的方式,并且最右边的基类中的那个成员变量会出现在派生类对象中。
  • 相关阅读:
    CodeDeploy 应用程序规范文件
    Lambda 函数的最佳实践
    路由策略
    AWS CodeStar
    使用 Lambda@Edge 在边缘站点自定义内容
    Step Functions
    将应用程序部署到 AWS Elastic Beanstalk 环境
    DynamoDB 静态加密
    web数据安全——防篡改
    【Spring】spring全局异常处理即全局model数据写入
  • 原文地址:https://www.cnblogs.com/xiangshancuizhu/p/2063637.html
Copyright © 2011-2022 走看看