我有一个设计,其中有 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/