【问题标题】:Object slicing within a two-dimensional array in c++C++中二维数组中的对象切片
【发布时间】:2014-04-14 07:37:35
【问题描述】:

您好,我在将派生类型对象存储在基本类型的二维数组中时遇到了一个小问题,而不会丢失存储在数组中的派生类型。

例如有以下 Base 和 Derived 类:

class Base{

}

class Derived: public Base{

}

有一点我创建了一个 Base 对象,如下所示:

Base objectB;

然后我将上面的对象转换为 Derived 类的类型,如下所示:

Base *referencePointer = &objectB;
Derived *derivedPointer = static_cast<Derived*>(referencePointer);

此时一切正常(如果我打印出 derivedPointer 的类型,它就是 Derived 类型)。

现在我有一个基类类型的二维数组,初始化如下:

Base *baseArray[5][5];

现在我将 derivedPointer 值输入到数组中,如下所示:

baseArray[x][y] = derivedPointer;

这是出现问题的地方,因为它存储在 referencePointer 中,但它变成了 Base 类型(对象切片),我不确定如何存储 referencePointer 值并将其类型保存在 Base 类型的数组中.

非常感谢任何帮助,

谢谢!

【问题讨论】:

  • 我想在一个数组中输入多个派生类,因为不同的对象将具有不同的功能。想象一下,有一个视频游戏,有不同类型的玩家,他们可以根据不同的类型进行不同的移动,但它们都具有相同的某些基本功能。
  • objectB 是基本类型,但您将其强制转换为派生类型(相关的类型但不是类型 objectB 实际上)。这是未定义的行为,不会像您期望的那样工作。也没有进行对象切片,因为您使用的是指针而不是对象值。
  • @CaptainObvlious 我对对象切片概念有点陌生,我认为这就是这里发生的事情,但我可能错了。演员阵容似乎有效?我使用 typeid(derivedPointer).name() 打印出来,它打印出 Derived 类型的类型,这意味着强制转换工作但是当我在输入后打印出以下 typeid(baseArray[x][y]).name() derivedPointer 它打印出 Base 类型的类型。
  • 未定义的行为意味着任何事情都可能发生,包括代码完全按预期工作。在另一个平台上构建它并运行它,结果可能会非常令人震惊。添加一些成员变量或虚函数,您的代码可能会以非常惊人的方式失败。
  • @Baraa,实际上,您的typeid() sn-ps 正在识别指针的类型,而不是指向对象的类型。

标签: c++ arrays inheritance types object-slicing


【解决方案1】:
Derived *derivedPointer = static_cast<Derived*>(referencePointer);

这是一个错误,因为referencePointer 实际上指向一个Base 对象。编译器不会神奇地将额外的位添加到Base 对象以将其转换为Derived 对象。为避免此错误,请使用 dynamic_cast 而不是 static_cast。然后您将能够检测到故障。

注意,Base 需要是多态的才能工作,它必须至少有 1 个虚函数。

顺便说一句,这与切片无关。即使referencePointer 指向Derived,也没关系:你有一个二维指针数组,可以放入Base *,它可能指向Derived 类型的对象。如果您有一个Base 的二维数组,则切片将是。

【讨论】:

  • “编译器不会神奇地将额外的位添加到 Base 对象以将其转换为 Derived 对象。为了避免此错误...” 很容易被采用这意味着使用dynamic_cast 附加所需的“额外位”。使用dynamic_cast 显示检查空指针值的示例也会更好地服务。奖励:在转换为引用类型时覆盖产生的 bad_cast 异常。
  • 请随时根据您的建议编辑我的答案 :)
  • 我的头像在你看来是黑色的吗?
【解决方案2】:

具有不同类型的能够移动的玩家的视频游戏 根据类型不同,但它们都有一定的基础 功能相同。

想象一下“某些基本功能”是在基类中实现的。这些方法可以很容易地作为公共或受保护的方法提供给任何派生类。从而消除重复代码。

现在想象基类提供了一个虚方法“void move(CoordinatesXYZ_t to, VelocityXYZ_t vel, AccelerationXYZ_t acc)”。

只需在派生类中添加具有相同签名的(虚拟)方法,每个派生对象就可以对游戏引擎的移动命令提供自己独特的响应。游戏引擎不需要知道它是什么类型的派生对象,就会调用正确的虚拟方法。

完全不需要垂头丧气。可以编写游戏引擎,使其根本不需要关心它正在处理什么样的派生类——只要派生对象符合接口。游戏引擎调用一个虚拟方法,这将导致调用适当的派生对象方法。

对于二维基指针数组的每个成员,实际方法可以是唯一的。

实际的方法甚至什么都不做(即一棵树可能不会移动。)

并且派生类不必提供 move 方法,除非所需的行为与基类的 move 方法提供的不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 2018-12-25
    相关资源
    最近更新 更多