C++模板和继承
我的C++框架有按钮。一个Button派生自Control。所以接受Control的函数可以将Button作为参数。到现在为止还挺好。C++模板和继承
我也有名单<
T>。但是,列表<
按钮>并非从List <
Control>派生,这意味着接受控件列表的函数不能将Button列表作为其参数。这很不幸。
也许这是一个愚蠢的问题,但我不知道怎样才能解决这个:(名单<
按钮>
应该从列表<
控制>
得出,但我不明白的方式来做到这一点“自动”
我不想告诉你,但是如果你正在使用实例列表来控制,而不是指向Control的指针,你的按钮无论如何都是垃圾(谷歌“对象切片”)。如果它们是指针列表,则可以按照其他人的建议将list<button*>
转换为list<control*>
,或者从list<button*>
复制到新的list<control*>
,并将即代入该函数。或者将该函数重写为模板。
所以,如果你以前有一个叫做DoSomething的功能了一个列表控件作为参数,你把它改写为:
template <class TControl>
void doSomething(const std::list<TControl*>& myControls) {
... whatever the function is currently doing ...
}
void doSomethingElse() {
std::list<Button*> buttons;
std::list<Control*> controls;
doSomething(buttons);
doSomething(controls);
}
如何使用指针?只是有list<Control*>
列表,把你喜欢到它的任何控制派生的对象。
而不是使用列表<按钮>,使用列表<控制* >的,这是指向按钮。这样,你的功能只有采取一种类型:列表<控制* >。
斯特劳斯对这个项目在他的FAQ:
Why can't I assign a vector<Apple*>
to a vector<Fruit*>
您可以通过两种方式解决这个问题:
- 榜上无名包含指向
Control
。然后接受List<Control*>
- 使您的功能成为模板。你仍然可以使用
List<Button>
和List<Control>
,但它更多的是样板代码,而且绝大多数时候不需要考虑。
这里是第二个选择的代码。第一种选择已经由其他答案解释:
class MyWindow {
template<typename T>
void doSomething(List<T> & l) {
// do something with the list...
if(boost::is_same<Control, T>::value) {
// special casing Control
} else if(boost::is_same<Button, T>::value) {
// special casing Button
}
}
};
要只为List<derived from Control>
限制doSomething
,需要一些更多的代码(寻找enable_if
,如果你想知道的)。
请注意,这种代码(看你有什么类型)是相当避免。你应该用虚拟功能来处理这些事情。向控制添加功能doSomething
,并在按钮中覆盖它。
一般情况下,C++的方式来写一个列表执行算法, 序列, ...是提供迭代器作为参数。
template < class iterator >
doSomething(iterator beg, iterator end);
这解决了列表按钮< *>不从列表衍生<控制*>。 (使用模板列表< T *>也会,但这是让你的函数通用 - 但不是真的)
根据我的经验,在迭代器上操作良好的模板化函数可能会很多(太多...)的工作,但它是“C++的方式”...
如果你走这条路线,考虑使用Boost.ConceptCheck。它会让你的生活变得更轻松。
好的,我的坏。我有指针列表,而不是对象列表。当然,将我的Button * s存储在Control *列表中可以修复函数调用问题,而且我通常会这样做,除非我想要一个Button *列表将它们用作Button,而不是Control。 – ggambett 2008-11-24 20:08:13
现在,你有什么?列表
如果你只有一个列表,并且想要特殊情况下单个元素,如果它们是按钮类型的,你将被迫使用dynamic_cast mate。 –
2008-11-24 20:23:18