向上转换不到真正的基类

时间:2017-12-01 12:02:54

标签: c++ upcasting

我有点担心这种糟糕的类层次结构的可怕问题。

class A {...}; // abstract
class B : public A {...}; // abstract
class C {...}; // abstract

class a1 : public B, public C {...}; // indirect inheritance of A
class c1 : public A, public C {...};

问题:是否可以将指针(引用)转换为C指针(引用)转换为A类。

据我所知,最好的解决办法是让C语言继承自A,但它仍会导致类a1(两个基础A)出现问题。

3 个答案:

答案 0 :(得分:3)

  

问题:是否可以将指针(引用)转换为C指针(引用)转换为A类。

除非类是多态的,即具有至少一个虚拟成员函数。在那种情况下,dynamic_cast可以用于侧面演员,如StoryTeller的回答所示。

但是,如果C指针(引用)指向继承A的子项,则可以先转换为该子指针,然后转到A

c1 c;
C& cref = c;
A& aref = static_cast<c1&>(cref);

这当然不一定是理想的,因为你不能只转换任何具体类型未知的任意C指针。

  

我知道最好的解决方案是让C级继承自A

如果你这样做了,那么所有C指针都可以隐式转换为A指针。

  

但是它仍然会导致类a1(两个基数A)出现问题。

要解决这些问题,你需要共享基础,即虚拟继承。

struct A {}; // abstract
struct B : virtual A {}; // abstract
struct C : virtual A {}; // abstract

struct a1 : B, C {}; // indirect inheritance of A
struct c1 : C {};

int main() {
    c1 c;
    C& cref = c;
    A& aref = cref;
}

答案 1 :(得分:3)

你要做的事情被称为“侧面演员”。内置的dynamic_cast表达式可以做到这一点。但它并不便宜,你最好不要在你的项目中关闭对RTTI的支持(你已经提到你的类是抽象的,因此需要虚函数,其中RTTI的生成需要声明)。

请参阅 Live

#include <cassert>

struct A {
    virtual ~A() = default;
};

struct B : public A {
    virtual ~B() = default;
};

struct C {
    virtual ~C() = default;
}; 

struct a1 : public B, public C {
    a1() = default;
    virtual ~a1() = default;

}; // indirect inheritance of A

int main() {
    a1 a;

    C* c = &a;

    assert(dynamic_cast<A*>(c) != nullptr);

    return 0;
}

但我认为你对需要重新设计课程的看法是非常有道理的。不应该出现侧面演员的需要。

答案 2 :(得分:0)

上述两个答案都是正确的,但我认为第一个答案更为广泛。 我可能会使用的另一个解决方案是创建一个奇怪的访问者,例如:

PointerCreator
{
  void visit ( const a1 & _a )
  {
    m_pointerToA = &_a;
  }

  void visit ( const c1 & _c )
  {
    m_pointerToA = &_a;
  }

  A * m_pointerToA;
};

PointerCreator pC;
a1.accept( pC );
A& = *pC.m_pointerToA;