我在层次结构中有不同类型的句柄。
class Handle { common data }
class HandleA : Handle { data specific to a }
class HandleB : Handle { data specific to b }
代码的大多数部分只处理句柄。但是某些部分(HandleA / HandleB的“管理器”)需要访问子类中的数据。 例如:
void ManagerA::DoSomething(Handle handle)
{
// needs access to data in handleA
}
是否有任何不涉及投射的解决方案?
到目前为止我的想法:
- 将其他数据保存在ManagerA / B中的地图内,并使用句柄查找该数据(附加散列表查找)
- 在句柄中调用多态方法(handle.DoSomething())调用适当的管理器方法(每个句柄需要一个额外的指针)
- 拧紧并使用铸件
有什么想法吗?我错过了什么吗?
由于
答案 0 :(得分:7)
接收参数按值,正如您所做的那样:
void ManagerA::DoSomething(Handle handle)
将传递的参数中的任何内容“切掉”超出Handle
实例所包含的内容,因此您的handle
参数将具有 NO “额外数据”。你绝对需要传递指针或引用(当然,如果不需要修改数据,可能是const
。)
话虽这么说,正常的多态方法涉及在基类中定义虚方法并在子类中适当地覆盖它们。为什么不遵循这样一个完全正常的架构而不是与反对 OO方法?可能有正当理由(例如在visitor
模式上采用某种变体等),但你只是没有解释足够的力量让我们能够沿着这些方向提供帮助;根据提供的信息,我必须建议“重新架构以使用虚拟方法”。
答案 1 :(得分:4)
如果它的数据只针对一个 - 而且只有一种类型,请使用dynamic_cast<T>
,这就是它的用途。否则在基类中声明一个虚函数。
编辑:任何解决方案都不可能在运行时产生可衡量的性能差异。
答案 2 :(得分:1)
我不会对句柄使用多态 - 作为句柄而不是指针,它们应该绝对隐藏引用对象的实现。如果使用虚函数,句柄的用户可以调用这些函数,这肯定是个坏主意。
两种常见的解决方案是投射和使用地图。如果是后者,你的句柄甚至不必是一个类 - 它也可以是一个int左右。在Windows上,句柄是void *指针。我不知道指针背后是什么,但我真的不在乎。就我而言,这就是句柄的重点。
答案 3 :(得分:0)
如何将DoSomething
的签名更改为:
void ManagerA::DoSomething(HandleA handle)
答案 4 :(得分:0)
你的第一个和第三个想法是有效的。另一个想法是使用double-dispatch(我不知道维基百科的文章是否可以理解:Meyer的More Effective C++中的原始文章/解释是20多页长),这意味着实现像这样的虚拟方法Handle::DoSomething(Manager&)
。
答案 5 :(得分:0)
另一种可能性是在每个句柄中存储具体类型,可能是整数或枚举。您要么对所有可能的具体句柄类型进行硬编码,要么使用某种类型的注册机制。显然这种方法有其自身的缺点,但它是另一种可能性,你没有提到。这是X-Windows用于事件类型的方法。事件数据结构是所有可能事件数据的并集,其中一个类型变量指示特定事件的真实数据类型。不是说它很好,只是说它是一个选项,不需要动态铸造。
enum HandleType
{
HANDLE_TYPE_A,
HANDLE_TYPE_B
};
class Handle
{
private:
HandleType _type;
protected:
Handle(HandleType type) :
_type(type)
{}
public:
HandleType get_type() const
{ return _type; }
};
class HandleA
{
HandleA() :
Handle(HANDLE_TYPE_A)
{}
};
void ManagerA::DoSomething(Handle& handle)
{
if (handle.get_type() == HANDLE_TYPE_A)
do_something();
}