除了 JoshD 的建议之外,您还可以使用 visitor pattern 为其他转换敞开大门。
使用协变返回类型向 Sprite 层次结构添加方法 dispatch_visit:
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 ); }
};
这允许每个对象通知转换器它的动态类型——本质上,动态分派到并行类型,甚至是并行类型层次结构。在编写代码时,其他所有内容都几乎可以正常工作……根据静态参数类型,从转换器的 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 (); }