我的C++框架有一个按钮(Button)类,它派生自控件(Control)类。因此,接受Control的函数可以将Button作为其参数。目前为止还好。
我还有一个List<T>(列表)类。然而,List<Button>并没有从List<Control>派生出来,这意味着接受控件列表的函数无法将按钮列表作为其参数。这很不幸。
也许这是个愚蠢的问题,但我不知道怎么解决:( List<Button>应该从List<Control>派生出来,但我不知道如何"自动"完成这个过程。
我的C++框架有一个按钮(Button)类,它派生自控件(Control)类。因此,接受Control的函数可以将Button作为其参数。目前为止还好。
我还有一个List<T>(列表)类。然而,List<Button>并没有从List<Control>派生出来,这意味着接受控件列表的函数无法将按钮列表作为其参数。这很不幸。
也许这是个愚蠢的问题,但我不知道怎么解决:( List<Button>应该从List<Control>派生出来,但我不知道如何"自动"完成这个过程。
Stroustrup在他的FAQ中有一个条目:
为什么不能将vector<Apple*>
赋值给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<派生自Control>
,需要添加更多代码来限制doSomething
的使用(如果您想了解,可以查找enable_if
)。
请注意,这种代码(查看类型)应该尽量避免。您应该使用虚函数来处理此类事情。在Control中添加一个函数doSomething
,并在Button中覆盖它。
list<Control*>
列表,并将您喜欢的任何继承自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*>而不是List<Button>,这样指向的是Buttons。这样,您的函数只需要采用一个类型: List<Control*>。
template < class iterator >
doSomething(iterator beg, iterator end);
这解决了List< Button* >不是从List< Control* >派生的问题。(使用模板List< T* >也可以,但这有点使您的函数泛型但又不完全)
根据我的经验,编写操作迭代器的良好模板化函数可能需要很多(太多...)工作,但这是“C++方式”...
如果您选择这条路,请考虑使用Boost.ConceptCheck。它会让您的生活变得轻松得多。