转换指向基类的指针列表
我有一个设计,其中有一个基指针的 std::list
,我想将其转换为添加行为的并行列表。我遇到的问题是,我尝试用来进行转换的对象在调用它时不知道实际类型是什么。
我很可能错过了一些微妙的东西,并且有一个简单的修复方法。但是,如果这是一个设计缺陷(我在其他帖子中看到过这一点),解决这个问题的适当方法是什么?
假设如下:
class Sprite { /* ... */ };
class Character : public Sprite {};
class Markup : public Sprite {};
这些被构造(基于某些输入)到 std::liststd::list
std::list
std::list
std::list<精灵*>
。我想做的就是最终获取列表并将其转换为适合输出操作的并行结构。例如,假设:
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>
这导致我提出我的问题。这个问题的最佳解决方案是什么——重新设计还是其他方式?
谢谢。
I have a design where I have a std::list
of base pointers that I'd like to transform into a parallel list that adds behavior. The problem I'm having is that the object that I'm trying to use to do the transform doesnt know what the actual types are when it is invoked.
It's quite possible that I'm missing something subtle and that there is an easy fix. However, if this is a design flaw (I've seen this suggested in other posts) what is the appropriate way to approach this?
Suppose the following:
class Sprite { /* ... */ };
class Character : public Sprite {};
class Markup : public Sprite {};
These are constructed (based on some input) into a std::list< Sprite * >
. What I'd like to do is eventually take the list and transform it into a parallel structure suitable for output operations. For instance, given:
class HTMLSprite { /* ... */ };
class HTMLCharacter : public HTMLSprite {};
class HTMLMarkup : public HTMLSprite {};
I'd ideally like to do something like
std::transform(sprites.begin (), sprites.end (), html.begin (), HTMLConvert);
with something like
struct HTMLConvert_ {
HTMLSprite * operator () (const Character * c) { return new HTMLCharacter (); }
HTMLSprite * operator () (const Markup * c) { return new HTMLMarkup (); }
} HTMLConvert;
Now, I get the error
call of `(HTMLConvert) (const Sprite* const&)' is ambiguous
HTMLSprite* HTMLConvert::operator()(const Character*) const <near match>
Which leads me to my question. What is the best solution to this problem - redesign or otherwise?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
除了 JoshD 的建议之外,您还可以使用访问者模式为其他转换敞开大门。
使用协变返回类型将方法
dispatch_visit
添加到 Sprite 层次结构:这允许每个对象通知转换器其动态类型 - 本质上是动态分派到并行类型,甚至是并行类型层次结构。其他一切在编写代码时几乎都能正常工作……根据静态参数类型,在转换器的operator()()函数中选择最佳候选者。
哦,您需要将“缺失的函数”添加到转换器中:
嗯,重复的函数可以通过模板封装……如果您想要
可访问 模板自动判断
dispatch_visit
的返回类型。如果您不喜欢principal_base
,您可以将其排除。In addition to JoshD's suggestion, you can keep the door open for other transformations by using the visitor pattern.
Add a method
dispatch_visit
to the Sprite hierarchy, using covariant return types:This allows each object to notify the converter of its dynamic type — essentially, a dynamic dispatch into the parallel type, or even a parallel type hierarchy. Everything else pretty much works as your code is written… the best candidate is chosen among the
operator()()
functions of the converter, based on the static parameter type.Oh, you'll need to add the "missing function" to the converter:
Hmm, that repetitive function could be encapsulated by a template… this only seems to work in C++0x if you want the
visitable
template to automatically determine the return type ofdispatch_visit
. If you don't likeprincipal_base
you can factor it out.我建议为每个类添加转换为 HTML 类型的功能。因此,您将拥有一个虚拟
Convert
函数作为Sprite
的成员,并且每个派生类都可以重写它。然后,当您在Sprite *
列表上调用Convert
函数时,它将调用适当的转换器。您需要转发声明返回类型 (HTMLSprite
)。可能有更优雅的方法,但这个想法允许您使用虚函数。
您的建议的问题在于,数组中的指针都是
Sprite *
类型,无论它们实际指向什么,因此Sprite *
将传递给您的功能。相反,使用类似 mem_fun 的东西来创建一个将调用该成员的结构;这将通过虚拟调用调用适当的函数:如果您需要我澄清任何内容,请评论。
I'd suggest adding the function to convert to HTML type to each class. So you'd have a virtual
Convert
function as a member ofSprite
and each derived class can override it. Then when you call theConvert
function on your list ofSprite *
s, it will call the appropriate converter. You'll need to forward declare the return type (HTMLSprite
).There are probably more elegant ways, but this idea allows you to use virtual functions.
The problem with your suggestion is that the pointers in the array are all type
Sprite *
regardless of what they actually point to, so aSprite *
is what will be passed to your function. Instead, use something like mem_fun to make a struct that will call the member; this will call the appropriate function through a virtual call:Comment if you need me to clarify anything.
抽象工厂怎么样?
How about an abstract factory?
由于您的转换需要了解要转换的所有类型,并且它也正在执行映射函数。
这是我的快速技巧
As your convert will need to know about all the types to convert from and too it is performing a mapping function.
Here is my quick hack