不向上转换为真正的基础 class
Upcasting not to real base class
我有点被糟糕的 class 层次结构所困扰。
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 的指针(引用)转换为指向 class A 的指针(引用)
我知道最好的解决方案是让 class C 继承自 A,但它仍然会导致 class a1(两个基数 A)出现一些问题。
The question: is it possible convert a pointer(reference) to C into pointer(reference) to class A.
除非 类 是多态的,即至少有一个虚拟成员函数。在这种情况下,dynamic_cast 可用于侧投,如 StoryTeller 的回答所示。
但是,如果 C
指针(引用)指向继承 A
的子指针,那么您可以先向下转换为该子指针,然后再转换为 A
。
c1 c;
C& cref = c;
A& aref = static_cast<c1&>(cref);
这当然不一定是理想的,因为您不能只转换具体类型未知的任意 C
指针。
I understand that best solution is to make just class C inherited from A
如果您这样做,那么所有 C
指针都可以隐式转换为 A
指针。
but still it can cause some problems with class a1 (two base 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;
}
您正在尝试做的事情叫做 "side-cast"。内置的 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;
}
但我认为您需要重新设计 类 的观点是非常有道理的。应该不需要做旁白。
上面的两个答案都是正确的,但我认为第一个答案得到了更广泛的解释。
我可能会使用的另一个解决方案是创建一个奇怪的访问者,例如:
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;
我有点被糟糕的 class 层次结构所困扰。
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 的指针(引用)转换为指向 class A 的指针(引用)
我知道最好的解决方案是让 class C 继承自 A,但它仍然会导致 class a1(两个基数 A)出现一些问题。
The question: is it possible convert a pointer(reference) to C into pointer(reference) to class A.
除非 类 是多态的,即至少有一个虚拟成员函数。在这种情况下,dynamic_cast 可用于侧投,如 StoryTeller 的回答所示。
但是,如果 C
指针(引用)指向继承 A
的子指针,那么您可以先向下转换为该子指针,然后再转换为 A
。
c1 c;
C& cref = c;
A& aref = static_cast<c1&>(cref);
这当然不一定是理想的,因为您不能只转换具体类型未知的任意 C
指针。
I understand that best solution is to make just class C inherited from A
如果您这样做,那么所有 C
指针都可以隐式转换为 A
指针。
but still it can cause some problems with class a1 (two base 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;
}
您正在尝试做的事情叫做 "side-cast"。内置的 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;
}
但我认为您需要重新设计 类 的观点是非常有道理的。应该不需要做旁白。
上面的两个答案都是正确的,但我认为第一个答案得到了更广泛的解释。 我可能会使用的另一个解决方案是创建一个奇怪的访问者,例如:
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;