我应该使用dynamic_cast <t>进行复制吗?</t>

时间:2009-04-09 09:43:43

标签: c# c++ dynamic-cast

  

更新1:

     

更正了无意义的代码!感谢您的评论,我制作了第一个片段的散列,oops。

     

更新2:

     

同样更新了问题标题,因为已经指出使用dynamic_cast是不必要的答案。

我在这里想要实现的是使用强类型的深层复制;我希望能够将Class2复制到Class2的另一个实例;但是,我也想使用Class1作为基础的CopyTo函数。这个想法来自我的C#体验,通常我只是将返回类型设为泛型(参见C#片段)。

void Class1::CopyTo(Class1 *c1)
{
    // Write data in to c1 from this instance.
    c1->exampleData = exampleData;
}

// Class2 inherits Class1
Class2 *Class2::Copy()
{
    Class2 *c2a = new Class2();
    CopyTo(c2a);

    Class2 *c2b = dynamic_cast<Class2*>(c2a);
    return c2a;
}

这就是我在C#中的方式:

public class Class1
{
    T Copy<T>()
        where T : Class1
    {
        /* Can't remember the best way to do this in C#;
         * basically if T was Class2 this would need to create
         * a new instance of that class, and the same goes for
         * Class1. */         
        T copy = createNewInstance();

        // Copy the data from this to 'copy'.
        copy.exampleData = exampleData;

        return copy;
    }
}

现在,与C#代码段相比,C ++代码段感觉很臭。是否有可能在没有指针的情况下做到这一点,或者这是最佳实践?

7 个答案:

答案 0 :(得分:1)

我不清楚你在问什么,但要注意当你说:

 Class2 *c2 = dynamic_cast<Class2*>(c1);

强制转换的结果可能为NULL,您必须检查此内容。

答案 1 :(得分:1)

您应该更多地处理代码段。 GetSomethingCopy正在创建一个传递给CopyTo的Class2类型的指针。 CopyTo尝试调用从未初始化的接收指针的成员函数:分段错误,程序死亡。

即使没有杀死应用程序,你也试图将 dynamic_cast 从Class2 *转换为Class2 *,这就是什么都不做。如果您打算从CopyTo转换返回的值,则必须知道不能在void *上使用dynamic_cast。您必须更改CopyTo签名以返回Class1(以便以后可以将其强制转换)或在void *上使用static_cast。

请注意,Copy是Class1中的一个虚函数,实际上是在Class2中执行的,并且创建了一个Class2对象,否则返回的元素将不是Class2,而是Class1。

CopyTo方法的名称令人困惑,因为它不是将复制到参数而是复制参数。

毕竟,我仍然不知道你在问什么。你想在哪里使用堆栈内存?您可以将堆栈分配的元素传递给函数,但是返回指向堆栈分配元素的指针/引用也是一个分段错误:当函数结束并且接收器将留下悬空指针/引用时,对象将被销毁。

现在,如果你的问题更能理解你是否可以在堆栈分配元素上使用dynamic_cast,那么你可以(假设Class2继承自Class1):

void f()
{
   Class2 c2;
   Class1 &c1 = c2; // c1 is a Class1 reference to a Class2 object

   dynamic_cast<Class2&>(c1).class2method(); 
   // or:
   dynamic_cast<Class2*>(&c1)->class2method();
}

如果您更新代码,请在此回答中发表评论,以便我注意到并可以在今晚更正。

答案 2 :(得分:0)

该代码没有任何意义如上所述......无论如何我“猜测”如果你没有使用void *作为回报,你可以使用静态转换吗?

好了,现在代码是有道理的。

您不需要任何动态强制转换,它已经是Class2类型。

答案 3 :(得分:0)

在CopyTo函数中,您将返回指向在堆栈上创建的对象的指针 - 这是不可能的,因为当函数返回时,指针指向的对象将被销毁。

在回答您的问题时,您可以在指针或引用上使用dynamic_cast。在您的情况下,我可能使用new而不是堆栈分配要动态返回的对象,然后您可以安全地返回指针。但是,我倾向于使用dynamic_cast作为潜在的代码气味,以及应该使用虚函数的标志。

答案 4 :(得分:0)

不,dynamic_cast仅适用于指针和引用。无论如何你都无法安全地返回你在堆栈上分配的任何东西,所以在这种情况下我不确定你打算如何修改你的代码。

答案 5 :(得分:0)

我不确定你想要实现什么,因为代码仍然没有多大意义。但是,我认为以下内容应该与您正在尝试的内容相近。请注意,我使用堆内存:它不是必需的,它会泄漏内存。

template <typename T>
T Class1::Copy()
{
    T instance;
    CopyTo(&instance);
    return instance;
}

这是有效的,因为您将instance的(多态)指针传递给CopyTo的{​​{1}}方法。

然后你可以像这样调用代码:

Class1

然而,这段代码仍然气味,因为它不是惯用的C ++:在C ++中,你通常会编写一个复制构造函数。后期绑定Class2 x1; // Fill x1 Class2 x2 = x1.Copy<Class2>(); 方法确实存在,但它们很少需要,并且上面不是后期绑定(但是你的C#代码也没有)。

答案 6 :(得分:0)

啊,现在问题很明显了。答案在技术上是否定的,而不是使用dynamic_cast&lt;&gt;,但我真的没有理解你为什么要这么做。看来你只是想要

void Class1::CopyTo(Class1& c1)
{
    // Write data in to c1 from this instance.
    c1.SomeIntValue = SomeIntValue;
}

// Class2 inherits Class1
Class2* Class2::Copy()
{
    Class2 *c2 = new Class2();
    CopyTo(*c2);
    return c2;
}
//or more idiomatic
Class2 Class2::Copy()
{
    Class2 c2
    CopyTo(c2);
    return c2;
}