C++ 多态句柄

C++ 多态句柄,c++,C++,我在层次结构中有不同类型的句柄 class Handle { common data } class HandleA : Handle { data specific to a } class HandleB : Handle { data specific to b } 代码的大多数部分只处理句柄。但是有些部分(HandleA/HandleB的“管理器”)需要访问子类中的数据。 例如: 有没有不涉及铸造的解决方案 到目前为止我的想法: -将附加数据保存在ManagerA/B中的映射内,并使用

我在层次结构中有不同类型的句柄

class Handle { common data }
class HandleA : Handle { data specific to a }
class HandleB : Handle { data specific to b }
代码的大多数部分只处理句柄。但是有些部分(HandleA/HandleB的“管理器”)需要访问子类中的数据。 例如:

有没有不涉及铸造的解决方案

到目前为止我的想法:
-将附加数据保存在ManagerA/B中的映射内,并使用句柄查找该数据(附加哈希表查找)
-在句柄(handle.DoSomething())中具有调用appropiate manager方法的多态方法(每个句柄中都需要一个额外的指针)
-拧上螺丝并使用石膏

有什么想法吗?我错过什么了吗


谢谢

如果它的数据只针对一种——而且只有一种类型,请使用
dynamic\u cast
,这就是它的用途。否则,在基类中声明一个虚函数


编辑:任何解决方案都不可能在运行时产生可测量的性能差异。

DoSomething
的签名更改为:

void ManagerA::DoSomething(HandleA handle)

我不会对句柄使用多态性——作为句柄而不是指针,它们应该绝对隐藏引用对象的实现。如果使用虚拟函数,句柄的用户可以调用这些函数,这肯定是个坏主意


两种常见的解决方案是强制转换和使用地图。如果是后者,您的句柄甚至不必是类——它也可以是int左右。在Windows上,句柄是void*指针。我不知道指针后面到底是什么,但我真的不在乎。就我而言,这就是手柄的问题。

你的第一个和第三个想法会奏效。另一个想法是使用(我不知道维基百科的那篇文章是否可以理解:Meyer的原始文章/解释有20多页长),这意味着实现一个虚拟方法,如
Handle::DoSomething(Manager&)

按值接收参数,就像您在:

void ManagerA::DoSomething(Handle handle)
将“切掉”传入参数中超出
Handle
实例所包含内容的任何内容,因此
Handle
参数将没有额外数据。您绝对需要通过指针或引用进行传递(当然,如果数据不需要修改,可能是
const


也就是说,正常的多态方法涉及在基类中定义虚拟方法,并在子类中适当地重写它们。为什么不遵循这样一个完全正常的体系结构,而不是反对OO方法呢?可能有合理的理由(例如,在
访客
模式上采用某种变体等),但您只是没有解释足够的力量,我们无法沿着这些路线提供帮助;根据提供的信息,我不得不建议“重新构造以使用虚拟方法”。

另一种可能性是在每个句柄中存储具体类型,可能是整数或枚举。您可以硬编码所有可能的具体句柄类型,或者使用某种类型的类型注册机制。显然,这种方法有其自身的缺点,但这是另一种可能性,您没有提到。这是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();
}

为什么你要避免调用DyrimCyCasic来获取子类HANLLX对象?可能是因为在很多C++教材中,C铸造有“坏的因果报应”:哨子:如果不是OpKy,那么它真的是一个句柄吗?如果您知道句柄是什么,并且需要将其用作正确的类型,那么为什么不使用cast呢?演员阵容有什么问题?Handle和HandleA&HandleB之间的私人继承是故意的吗?非公共继承通常意味着继承是一个实现细节,即,在这种情况下,您不希望类之外的代码将HandleA或HandleB视为句柄。这称为向下投射:
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();
}