Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 类层次结构中动态_cast的替代方案_C++_Inheritance_Dynamic Cast_Virtual Functions - Fatal编程技术网

C++ 类层次结构中动态_cast的替代方案

C++ 类层次结构中动态_cast的替代方案,c++,inheritance,dynamic-cast,virtual-functions,C++,Inheritance,Dynamic Cast,Virtual Functions,我有一个类结构,不同子类的负载都继承自同一个抽象基类。这个基类之所以存在,是因为所有这些类都在编译时自注册到构建它们的工厂。这真的很好,让我不必在下游某处维护一个巨大的开关或任何其他流动机制 +---------------+ | Base | +--+---------+--+ | | +-------+-+ +-+-

我有一个类结构,不同子类的负载都继承自同一个抽象基类。这个基类之所以存在,是因为所有这些类都在编译时自注册到构建它们的工厂。这真的很好,让我不必在下游某处维护一个巨大的开关或任何其他流动机制

              +---------------+
              |     Base      |
              +--+---------+--+
                 |         |
         +-------+-+     +-+-------+
         |  Kid1   |     |  Kid2   |
         +----+----+     +----+----+
              |               |
  +---+---+---+               +---+---+---+
  |   |   |   | ...           |   |   |   | ....
但是,这些
Kid1
Kid2
类是不同的,问题是我必须在代码中的某个地方区分它们,我唯一拥有的是
Base
指针。我不想用这件事来打扰工厂,并且尽可能简单

我现在解决这个问题的方法是让
Base
对这两个兄弟姐妹有所了解。它有一个虚拟方法
type()
,它返回一个区别于
Kid1
Kid2
的枚举类型。两个孩子都忽略了这一点(基本上说我是KidX),这样我就知道我在和谁打交道。然后使用此类型将
dynamic_cast
Base
播送给两个孩子中的任何一个,然后程序继续进行

然而,这是正确的方法吗

例如,我可以添加更多的
virtual
方法作为基础,一方面只使用层次结构的一部分使用的方法来污染它,另一方面为我节省
dynamic\u cast


有什么想法吗?

您不需要
dynamic\u cast
dynamic\u cast
已经使用内部运行时类型信息来确定它是否能够将传递的指针/引用强制转换为所需的类型,但您已经通过
type()
方法对其进行了检查。在您的情况下,
static\u cast
就足够了,因为您已经自己提供了RTTI

或者,您也可以删除type()方法,直接使用
dynamic_cast
,如果无法将对象强制转换为所需类型,则会生成
nullptr


如果你真的想避免这样的事情,那么你必须将你想要的行为封装到
虚拟
方法中,这样无论你在哪里需要使用
Kid1
Kid2
,你都会有不同的实现,而不需要真正区分两者,只需让多态性发挥作用。

在多重继承中,dynamic_cast将根据需要移动指针,这是必须的。因此,摆脱它是危险的。如果您的系统扩展到某个地方使用MI,您可能会出现各种奇怪的行为。

也许您可以使用
typeid
操作符。因为:

N3337 5.2.8/2规定:

当typeid应用于类型为多态类类型的glvalue表达式(10.3)时,结果引用 指向std::type_info对象,该对象表示最派生对象(1.8)的类型(即动态 glvalue引用的类型

例如:

struct Base
{
    virtual void f(){} //to ensure that Base is polymorphic object
};

struct Derived: Base{};

struct AnotherDerived: Base{};



int main()
{
    Base *ptr = new AnotherDerived;

    if(typeid(*ptr) == typeid(Derived)) //Do not forget to dereference pointer, otherwise typeid() will return type_info for pointer itself
    {
         cout << "ptr is pointing to object of type Derived" << endl;
    }

    if (typeid(*ptr) == typeid(AnotherDerived))
    {
        cout << "ptr is pointing to object of type AnotherDerived" << endl;
    }

}
struct Base
{
virtual void f(){}//以确保Base是多态对象
};
派生结构:基{};
另一个派生的结构:Base{};
int main()
{
Base*ptr=新的另一个派生的;
如果(typeid(*ptr)=typeid(派生))//不要忘记取消引用指针,否则typeid()将返回指针本身的type_信息
{

cout我通常更喜欢在不使用强制转换的情况下获得所需类型的句柄。这意味着向基类添加方法:

virtual Kid1 *asKid1()
{
    return null;
}

virtual Kid2 *asKid2()
{
    return null;
}
然后,子类会根据需要覆盖这些:

// (in Kid1)
virtual Kid1 *asKid1() override
{
    return this;
}
尽管您的
Base
类仍然被额外的方法“污染”,但即使子类在将来被扩展,也只需要这两个方法

(您可以让它们返回引用而不是指针,在这种情况下,默认情况下它们应该引发异常)。

您可以尝试


您的
类型()的替代品
成员只需尝试对Kid1进行动态转换,然后Kid2…绑架,看看哪一个成功。不漂亮。只是指出这是一个替代方案。@JesperJuhl我也曾玩弄过这个想法,但不能忽略丑陋的
静态转换
,当向上移动和向上移动时,隐式转换也会正确地移动指针拥有类层次结构,包括多重继承。如果没有
dynamic\u cast
@CemKalyoncu,交叉转换将无法工作,因为它是“不安全的”在编译器不允许虚拟继承的情况下。这通常意味着在实践中使用虚拟继承是完全安全的;否则会出现编译时错误。@CemKalyoncu:请不要将ideone用于代码段。尽管他们的服务条款称这些代码段将“永远”托管,他们还是会删除这些代码段。该示例显示了一个没有给出编译器错误但代码正确运行的情况。也就是说,它不仅限于MI。它用于使用静态\u强制转换进行向下转换。@BenVoigt Ok,您推荐哪个站点?谢谢您的回答。您的建议基本上意味着50%的强制转换将失败。这不是很不可取吗?您说过需要在代码中区分它们,这也是不可忽视的,因为它会阻止多态性发挥作用。这是一个XY问题。首先解释为什么以及如何区分它们,以便我们能够提供合适的解决方案。感谢您的输入。我基本上是用额外的知识来做这件事的。我可以按照@Jack的建议去做简单地说“试试”@Montaldo当您需要区分它们时,为什么要使用指向基的指针?自注册结构需要一个通用的基类型,以便从工厂中构建。这一方面是一种幸事,但代价是这样的。仔细阅读OP的问题可以揭示为什么这个答案不可行。有一个基类
Base
,两个子类
Kid1
Kid2
,它们还有更多的子类