【问题标题】:Multiple virtual inheritance C++多重虚拟继承 C++
【发布时间】:2018-01-08 16:52:50
【问题描述】:

我遇到了多重继承问题,如果有人能帮助我,那就太好了。我正在编写一个最终归结为类似于此的情况

    class A {
public:
    A(){}
    virtual ~A() = 0;
    virtual void print()=0;
};
A::~A(){}

class B: public virtual A {
public:
    B():A(){}
    virtual ~B() = 0;
    virtual void print() {
        cout << "Hello" << endl;
    }
};
B::~B(){}

class C: public virtual A {
public:
    C():A(){}
    virtual ~C() = 0;
    virtual void print () {
        cout << "Bye" << endl;
    }
};
C::~C(){}

class D: public B, public C {
public:
    D():B(),C(){}
    virtual ~D(){}
    virtual void print(){}
};

int main()
{
    D d;
    A* a = &d;
    a->B::print(); //The statement leads to errors
    a->C::print(); //The statement leads to errors
}

我需要访问 B 类和 C 类中虚函数的实现。有没有办法做到这一点?

【问题讨论】:

  • 投射指针?
  • D* a = &amp;d; 解决了这个问题。
  • 你能给B版本一个你可以调用的别名或备用名称吗?
  • 嗨@maxim,实际上继承链很大,A 实际上继承自一堆其他类。我想实际上从上层类动态调度 print() 的执行,并且没有指向 D 的指针,这会杀死调度

标签: c++ multiple-inheritance diamond-problem


【解决方案1】:

类型A 根本不知道子类BC 中的实现。要呼叫这些成员,您首先必须将a 至少转换为BC,甚至D

D* aAsD = dynamic_cast<D*>(a);
if (aAsD) {
    aAsD->B::print(); 
    aAsD->C::print();
}

【讨论】:

  • 您好,不幸的是,在我的情况下,dynamic_cast 并不是一个有吸引力的解决方案,因为我的目标是嵌入式系统
  • 然而,static_cast 可能仍然被允许
  • @RaghurajTarikere • 当我使用 C++ 进行一些嵌入式编程时,我们不允许使用 C++ 的某些特性(被编译器开关禁用)。我们不能使用 RTTI、异常、虚拟多态性或流。为了构建你所拥有的那种结构,我们将使用包含和成员函数,将调度(thunk)转发到正确的成员对象。听起来您可以使用所有的 C++,但该技术可能对您有所帮助。
【解决方案2】:

要理解这一点,请暂时忽略继承:

  1. “A”类没有打印方法
  2. “B”类和“C”类有自己的打印方法
  3. “D”类本身没有打印方法。

现在将继承添加到等式中:

  1. 类“D”继承了“B”和“C”,所以它有两种打印方法
  2. 类 'B' 和 'C' 继承了 'A',但由于 'A' 没有打印方法,它们仍然具有相同的方法
  3. “A”类没有打印方法。

当您转换A* a = &amp;d 时,您正在将具有两种打印方法的类转换为没有打印方法的类。由于继承的力量,'A' 类打印方法现在被'D' 类中的方法重载,但'a' 变量仍然是'A' 类(具有来自'D' 的重载)。由于“A”不继承“B”或“C”,它不知道它们是什么。尝试使用它们时出现错误的原因。

解决方案就是不将“D”转换为“A”:

int main() {
    D d;
    d.B::print(); //Hello
    d.C::print(); //Bye
}

此外,如果您需要将“D”转换为“A”,则应相应地将其向上转换为 B 或 C:

int main() {
    D d;
    A* a = &d;
    dynamic_cast<B*>(a)->B::print();
    dynamic_cast<C*>(a)->C::print();
}

或 1 个动态演员版本:

int main() {
    D d;
    A* a = &d;
    D* dptr = dynamic_cast<D*>(a);
    dptr->B::print();
    dptr->C::print();
}

换句话说,在分别使用“C”和“B”之前,您必须将“a”向上转换为继承“C”和“B”的东西

【讨论】:

  • 重新解释转换(比嵌入式系统的动态转换更好)指向 B 或 C 的 A 指针,然后在它们上调用函数对我很有用。但它仍然使最终代码不可移植,这是一些令人担忧的问题
  • 如果不投射指针,就无法访​​问“B”或“C”打印方法。艰难,您可以访问所有“D”方法。你不能在 D 中创建一个相应地打印“B”或“C”的方法吗?也许用枚举作为参数
【解决方案3】:

A *a 不知道print()BC 内。您可能希望D 处理是否调用B::print()C::print()

class D: public B, public C {
public:
    D():B(),C(){}
    virtual ~D(){}
    virtual void print()
    {
       B::print(); //or some logic to call one of them
       C::print();
    }    
};

D d;
A* a = &d;
a->print(); 

【讨论】:

    【解决方案4】:

    对于像那样做 B::Print 或 C::print 的整个愿望似乎有些错误......尤其是当你在 D 中让它成为无操作时。

    这表明也许 D 不应该继承 B 和 C,而是包含一个 B 和一个 C。然后您可以将 B 和 C 与 D 分开公开,这可以作为 A 单独传递。

    显然,这可能不适用于您的扩展问题,但适用于您发布的问题;我会称之为继承滥用。

    【讨论】:

      猜你喜欢
      • 2017-03-31
      • 1970-01-01
      • 1970-01-01
      • 2014-11-06
      • 2010-09-22
      • 2015-11-21
      • 1970-01-01
      • 2013-11-19
      • 2012-10-11
      相关资源
      最近更新 更多