返回指向对象的参数指针

时间:2010-09-27 16:02:05

标签: c++ pointers casting

在C ++ for Windows中,我有一些对象工厂应该通过将指向对象的指针传递给Create函数并返回创建的对象来创建一系列Info对象。

void CreateInfoObject(AbstractInfo** info);  // The creation function 

AbstractInfo是一个基类,我们有许多类型的Info对象派生。

我以为我现在可以按如下方式创建一个Info对象:

MyInfoObject* InfoObj = NULL;  // derived from AbstractInfo object
InfoFactory fc;

fc.CreateInfoObject(&InfoObj); // Now I want to get my initialized pointer back

但它说不能做演员......出了什么问题?

错误:     无法从MyInfoObject ** _ W64转换为AbstractInfo **

编辑:第一个答案提到界面很可怕,看不到谁在分配等等......我怎样才能改进?

5 个答案:

答案 0 :(得分:8)

让我们考虑CreateInfoObject的可能实现:

void InfoFactory::CreateInfoObject(AbstractInfo** info)
{
  *info = new SuperInfo;
}

现在,SuperInfoMyInfoObject没有任何共同点吗?

这就是为什么一般来说,以下是禁止的:

struct Base {};
struct D1: Base {};
struct D2: Base {};

int main(int argc, char* argv[])
{
  Base** base = nullptr;
  D1* d = nullptr;
  base = d;
}

因为它允许D1指向不相关的东西。

有几种解决方案:

// 1. Simple
AbstractInfo* info = nullptr;
fc.CreateInfoObject(info);

// 2. Better interface
std::unique_ptr<AbstractInfo> info = fc.CreateInfoObject();

然后,如果您确定知道您实际上有MyInfoObject可以使用:

MyInfoObject* myInfo = static_cast<MyInfoObject*>(info);

或者如果您不确定:

MyInfoObject* myInfo = dynamic_cast<MyInfoObject*>(info);
如果myInfo没有指向nullptr(或派生)的实例,

会将info设置为MyInfoObject

请记住,你的界面非常可怕。它非常C-ish并且不清楚是否实际分配了内存......如果是,则负责处理内存。

修改

良好的 C ++风格中,我们使用RAII来表示所有权并确保清理。 RAII虽然不是很有说服力,但我自己更喜欢新的SBRM(Scope Bound Resources Management)。

这个想法是,不是使用裸指针,而是没有表明所有权(即你必须在其上调用删除吗?),你应该使用智能指针,例如unique_ptr

您还可以使用方法的return参数,以避免进行两步初始化过程(首先创建指针,然后使其指向对象)。这是一个简洁的例子:

typedef std::unique_ptr<AbstractInfo> AbstractInfoPtr;

// Note: if you know it returns a MyInfoObject
// you might as well return std::unique_ptr<MyInfoObject>
AbstractInfoPtr InfoFactory::CreateInfoObject()
{
  return AbstractInfoPtr(new MyInfoObject());
}

// Usage:
int main(int argc, char* argv[])
{
  InfoFactory factory;
  AbstractInfoPtr info = factory.CreateInfoObject();

  // do something

} // info goes out of scope, calling `delete` on its pointee

在这里,所有权没有歧义。

另外,请注意您在这里如何更好地理解您的问题:

  std::unique_ptr<MyInfoObject> info = factory.CreateInfoObject();

无法编译,因为您无法使用AbstractInfo*MyInfoObject*static_cast转换为dynamic_cast

答案 1 :(得分:3)

因为CreateInfoObject()采用指针指向AbstractInfo的指针,所以函数可能会返回不是<{1}}的实例/ em> AbstractInfo的实例。因此,您最终可能会指向MyInfoObject 实际指向MyInfoObject。{/ p>

DifferentInfoObject更改为MyInfoObject *InfoObj,它应该有效。不要使用AbstractInfo *InfoObj以外的任何内容丢弃转换,因为您不确定dynamic_cast<>是否返回该子类的实例。

答案 2 :(得分:3)

编译器告诉你什么是错的。当T和U彼此无关时,您无法将类型为T *的指针转换为U *类型的指针。这里,T = MyInfoObject *,U = AbstractInfo *,这些是两个不共享任何继承关系的不同指针类型。

答案 3 :(得分:2)

指向指针的指针不如指向对象的指针灵活。编译器将严格执行该类型,而不考虑继承树。

修复此代码的最安全方法是使用双重赋值:

MyInfoObject* InfoObj = NULL;  // derived from AbstractInfo object 
AbstractInfo* temp = NULL;
InfoFactory fc; 

fc.CreateInfoObject(&temp); 
InfoObj = dynamic_cast<MyInfoObject*>(temp);

答案 4 :(得分:0)

考虑在CreateInfoObject中发生。

假设还有AbstractInfo的另一个子类,请致电Foo

CreateInfoObject内,我们创建了一个新的Foo并将其分配给*info。 (允许向上翻。)

但我们现在在Foo内部MyInfoObject**,这是错误的。