c++ - 转换指向基类的指针列表

标签 c++ polymorphism transform

我有一个设计,其中有 std::list我想将其转换为添加行为的并行列表。我遇到的问题是,我尝试用来进行转换的对象在调用它时不知道实际类型是什么。

我很可能错过了一些微妙的东西,并且有一个简单的修复方法。但是,如果这是一个设计缺陷(我在其他帖子中看到过这一建议),那么解决这个问题的适当方法是什么?

假设如下:

class Sprite { /* ... */ };
class Character : public Sprite {};
class Markup : public Sprite {};

这些被构造(基于一些输入)到 std::list< Sprite * > 。我想做的就是最终获取列表并将其转换为适合输出操作的并行结构。例如,给定:

class HTMLSprite { /* ... */ };
class HTMLCharacter : public HTMLSprite {};
class HTMLMarkup : public HTMLSprite {};

我理想中想做类似的事情

std::transform(sprites.begin (), sprites.end (), html.begin (), HTMLConvert);

类似的东西

struct HTMLConvert_ {
  HTMLSprite * operator () (const Character * c) { return new HTMLCharacter (); }
  HTMLSprite * operator () (const Markup * c) { return new HTMLMarkup (); }
} HTMLConvert;

现在,我收到错误

call of `(HTMLConvert) (const Sprite* const&)' is ambiguous
HTMLSprite* HTMLConvert::operator()(const Character*) const <near match>

这引出了我的问题。这个问题的最佳解决方案是什么——重新设计还是其他方式?

谢谢。

最佳答案

除了 JoshD 的建议之外,您还可以使用 visitor pattern 为其他转换敞开大门。 .

使用协变返回类型将方法 dispatch_visit 添加到 Sprite 层次结构:

class Sprite{
    virtual HTMLSprite * dispatch_visit( HTMLConvert_ const &c ) const = 0;
};
class Character : public Sprite {
    virtual HTMLCharacter * dispatch_visit( HTMLConvert_ const &c ) const
        { return c( this ); }
};
class Markup : public Sprite {
    virtual HTMLMarkup * dispatch_visit( HTMLConvert_ const &c ) const
        { return c( this ); }
};

这允许每个对象通知转换器其动态类型——本质上是动态分派(dispatch)到并行类型,甚至是并行类型层次结构。其他一切在编写代码时几乎都能正常工作……根据静态参数类型,在转换器的 operator()() 函数中选择最佳候选者。

哦,您需要将“缺少的功能”添加到转换器中:

struct HTMLConvert_ {
  HTMLSprite * operator () (const Sprite * c) { return c->dispatch_visit( *this ); }
  HTMLCharacter * operator () (const Character * c) { return new HTMLCharacter (); }
  HTMLMarkup * operator () (const Markup * c) { return new HTMLMarkup (); }
} HTMLConvert;

嗯,重复的函数可以用模板封装……如果您希望 visitable 模板自动确定 dispatch_visit< 的返回类型,那么这似乎只在 C++0x 中有效。/。如果您不喜欢 principal_base,您可以将其排除。

#include <functional>

template< class T >
struct principal_base
    { typedef void type; };

template< class Client, class Visitor,
    class Base = typename principal_base< Client >::type >
struct visitable :
    virtual visitable< typename principal_base< Client >::type, Visitor > {
    virtual typename std::result_of< Visitor( Client * ) >::type
    dispatch_visit( Visitor const &v ) const
        { return v( static_cast< Client const * >( this ) ); }
};

template< class Client, class Visitor >
struct visitable< Client, Visitor, void > {
    virtual typename std::result_of< Visitor( Client * ) >::type
    dispatch_visit( Visitor const &v ) const = 0;
};

class HTMLSprite { /* ... */ };
class HTMLCharacter : public HTMLSprite {};
class HTMLMarkup : public HTMLSprite {};

class Sprite;
class Character;
class Markup;

struct HTMLConvert_ {
  HTMLSprite * operator () (const Sprite * c);
  HTMLCharacter * operator () (const Character * c);
  HTMLMarkup * operator () (const Markup * c);
} HTMLConvert;

class Sprite : public visitable< Sprite, HTMLConvert_ > {};
template<> struct principal_base< Character >
    { typedef Sprite type; };
class Character : public Sprite, visitable< Character, HTMLConvert_ > {};
template<> struct principal_base< Markup >
    { typedef Sprite type; };
class Markup : public Sprite, visitable< Markup, HTMLConvert_ > {};

//class Invalid : Character, Markup {};

HTMLSprite * HTMLConvert_::operator () (const Sprite * c)
    { return c->dispatch_visit( *this ); }
HTMLCharacter * HTMLConvert_::operator () (const Character * c)
    { return new HTMLCharacter (); }
HTMLMarkup * HTMLConvert_::operator () (const Markup * c)
    { return new HTMLMarkup (); }

关于c++ - 转换指向基类的指针列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3886907/

相关文章:

c++ - 为什么大多数最大的开源项目都是 C 语言?

c++ - 如何更改初始化的变量取决于虚函数

haskell - 当没有绑定(bind)时,haskell 中缺乏多态推断

c++ - 执行 "delete this"时缺少虚拟析构函数

css - Safari(手机+桌面)分组CSS关键帧动画

c++ - 数字常量 long int 和 long double 的后缀怎么可能都是 l/L?

c++ - 这些构造函数是否正确?

c++ - 一个 vector 在 2500 万个 vector 中的查找距离

r - 使用 ggplot 绘制辅助轴

math - 将矩形变成圆环