C++多态类是否可能没有任何功能?

Mal*_*ous 5 c++ polymorphism

我试图创建一些只包含数据成员(没有函数)的类,但我希望它们是多态的 - 我的意思是我将通过指向基类的指针传递对象,我需要能力dynamic_cast它们是特定的派生类型(NULL如果实例不是给定类型,则得到结果值.)

举个例子,我有一个项目:

struct Item {
    int x, y;
}
Run Code Online (Sandbox Code Playgroud)

我还有一个移动的项目,另一个包含文本:

struct MovingItem: virtual public Item {
    int speedX, speedY;
}

struct TextItem: virtual public Item {
    std::string text;
}
Run Code Online (Sandbox Code Playgroud)

据推测,我必须使用上面的虚拟继承,因为我还想要一个移动并有文本的项目,但我只想要顶层的一组坐标Item:

struct MovingTextItem: virtual public MovingItem, virtual public TextItem {
}
Run Code Online (Sandbox Code Playgroud)

这些都可以正确地定义,但是当我尝试dynamic_castItem *,看看它是什么类型,我的编译器抱怨说,源类型不是多态.

void example(Item *i) {
    MovingTextItem *mti = dynamic_cast<MovingTextItem *>(i);  // error!
}
Run Code Online (Sandbox Code Playgroud)

如果我使用虚函数而不是数据成员重新实现整个事情,这将有效,但这似乎是浪费,因为我永远不需要覆盖任何东西.

我能想到的唯一解决方法是将一个type成员添加到基Item类,并检查它而不是使用dynamic_cast,如果它是正确的类型,则使用static_cast.(缺点是我必须知道某处的所有对象类型,因此分配的type值不会发生冲突.)

这是最好的解决方案,还是有另一种方式?

澄清

为了论证,想象一下我将每个对象类型写入文件. MovingItem转到一个文件,TextItem转到另一个文件,然后MovingTextItem转到这两个文件.因此,拥有一个实现每个接口的基类将无法工作,除非我能以某种方式告诉哪些接口正在使用,以便将它们写入正确的文件.

krl*_*mlr 6

如果你添加一个虚函数,这些类将获得一个vtable,这样就dynamic_cast可以了.一个无操作的虚拟析构函数就可以了.(正如Torsten所指出的那样,在你的情况下甚至可能有必要,因为你有非POD成员.)

但是,根据我自己的经验(我多年来一直反对这一点!)我强烈建议不要在这种特殊情况下继承.请改用聚合.喜欢构成而不是继承?您可能必须创建几个转发器,但是通过这种方式获得的灵活性得到了回报(在以后能够在不影响整个系统的情况下更改实现方面).

认为项目的速度,此外,文本替代的位置,说不知何故有速度和文本的项目和一些魔术继承的位置.如果您以后想要一个速度但没有已知位置的物品怎么办?

要在聚合场景中实现结果,请定义构成与特定功能相关的合同的"接口".也不需要虚拟继承:"接口"只是具有纯虚函数的类.另请参阅:"编程到接口"是什么意思?(如果你想要可维护的软件,另一个重要的规则.)

你可以定义四个"接口"(类只有纯虚函数): ,,Position 和.继承自前三个并且没有定义任何函数本身.您为前三个接口提供"参考实现"."参考impl." for 有三个数据成员(前三个接口的ref.inpl.)并转发到这些实现.现在你可以使用,例如,你需要有位置的东西,而不必知道究竟是什么.也有效.SpeedTextItemItemItemPositiondynamic_cast

你也可以定义一个接口ItemBase,没有虚方法有Position,SpeedText从该接口继承.这将允许您通过相同的基本类型访问所有功能,并动态测试子接口的可用性.virtual我认为仍然没有必要继承...