7

给定 的基类gameObject和 的派生类animatedGameObject,我认为将它们的所有实例存储在std::vector. 如果向量GameObjects被声明为 的基类型gameObject*,则派生对象实例需要强制转换。

例子:

vector<gameObject*> GameObjects;

gameObject A* = new gameObject( ...init... ); 
animatedGameObject B* = new animatedGameObject( ...init... );

GameObjects.push_back(A);
GameObjects.push_back(B);

// to access the animatedGameObject functions:
static_cast<animatedGameObject*>(GameObjects[1])->functionUniqueToAnimated();

像往常一样害怕,我求助于 Scott Meyers(Effective C++,第 3 版),他在这个主题上写道:

许多程序员认为强制转换只会告诉编译器将一种类型视为另一种类型,但这是错误的。任何类型的类型转换(通过强制转换显式或编译器隐式转换)通常会导致代码在运行时执行。

我已经阅读了他的第 27 条:最小化施法两次,但鉴于我对此缺乏经验,我无法回答一个简单的问题“这是一个愚蠢的事情吗?”

我应该提到,与调用无关的事情是一件愚蠢的事情有几个原因static_cast。这些问题按重要性排序如下:

  1. static_cast在上面的示例中,我没有看到使用 的一些可能的风险吗?
  2. 有没有比std::vector这种方法更好的数据结构?(仅当有一个很明显时,我才不会要求您为我做研究。)

这是我第一次在这里提问,如有必要,请提前道歉。

4

2 回答 2

7

static_cast不是适合这项工作的工具,除非您知道指针指向animatedGameObjecta 而不是 a gameObject。您使用什么数据结构来存储这些信息?

在基指针之后确定派生对象的类型是动态调度或dynamic_cast. 在您的示例中,调用GameObjects[1]->draw()应该在没有强制转换的情况下工作,因为draw应该是一个虚函数。否则,您可以使用dynamic_cast< animatedGameObject & >( * GameObjects[1] )断言该对象是animatedGameObject,std::bad_cast如果不是,则抛出异常。(这仍然需要一个virtual函数 in class gameObject,通常是它的析构函数。)

但是static_cast对多态派生类型进行操作是一种代码味道。


你还问std::vector这个用例是否是一个好的数据结构。它是,但不是“裸”指针的向量。C++11 现在提供了“智能指针”内存管理类,它们可以为您执行newdelete为您呈现实际的运算符几乎已经过时。调查std::unique_ptr这个案子。

于 2013-07-01T03:07:47.723 回答
1
  1. 如果 gameObjects[1] 不是 animatedGameObject,应用程序将(很可能)可怕地死掉。
  2. 如果 draw() 是 gameObject 中存在的虚拟方法,则无需转换。

通常,将基类转换为派生类是不安全的。在这些情况下,使用 dynamic_cast 是有意义的。如果无法执行转换,Dynamic_cast 返回 NULL。

有没有比这更好的数据结构

好吧,如果您的游戏对象没有在其他地方自动删除,那么使用类似std::vector<std::shared_ptr<gameObject> >. 但是,标准共享指针可能会引入隐藏的开销(额外的新/删除,在最坏的情况下,如果它们被设计为线程安全的,它们甚至可能引入多线程互斥锁),因此您应该确保这些开销与您的目标。

于 2013-07-01T03:14:23.613 回答