简体   繁体   English

C ++模板和继承

[英]C++ templates and inheritance

My C++ framework has Buttons. 我的C ++框架有Buttons。 A Button derives from Control. Button来自Control。 So a function accepting a Control can take a Button as its argument. 因此,接受Control的函数可以将Button作为其参数。 So far so good. 到现在为止还挺好。

I also have List < T>. 我也有List < T>。 However, List < Button> doesn't derive from List < Control>, which means a function accepting a list of Controls can't take a list of Buttons as its argument. 但是,List < Button>不是从List < Control>派生的,这意味着接受控件列表的函数不能将Buttons列表作为其参数。 This is unfortunate. 这很不幸。

Maybe this is a stupid question, but I don't see how can I solve this :( List < Button > should derive from List < Control > , but I don't see a way to make this happen "automatically". 也许这是一个愚蠢的问题,但我不知道如何解决这个问题:( List < Button >应该来自List < Control > ,但我没有看到一种方法来“自动”实现这一点。

Stroustrup has an item on this in his FAQ: Stroustrup在他的FAQ中有一个项目:

Why can't I assign a vector<Apple*> to a vector<Fruit*> 为什么我不能将vector<Apple*>指定给vector<Fruit*>

You can solve it in two ways: 您可以通过两种方式解决它:

  • Make the List contain pointers to Control . 使List包含指向Control指针。 Then accept List<Control*> 然后接受List<Control*>
  • Make your function a template. 使您的功能成为模板。 You can still use List<Button> and List<Control> then, but it's more boilerplate code, and not necassary most of the time. 你仍然可以使用List<Button>List<Control> ,但它更多的是样板代码,而不是大多数时候的neopssary。

Here is code for the second alternative. 这是第二种替代方案的代码。 The first alternative is already explained by other answers: 第一种选择已经由其他答案解释:

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

        }

    }
};

To restrict doSomething only for List<derived from Control> , some more code is needed (look for enable_if if you want to know). 要仅为List<derived from Control>限制doSomething ,需要更多代码(如果您想知道,请查找enable_if )。

Note that this kind of code (looking what type you have) is rather to avoid. 请注意,这种代码(看你有什么类型)是要避免的。 You should handle such things with virtual functions. 你应该用虚函数来处理这些事情。 Add a function doSomething to Control, and override it in Button. 添加一个函数doSomething to Control,并在Button中覆盖它。

How about using pointers? 使用指针怎么样? Just have a list of list<Control*> and put whatever Control-derived objects you like into it. 只需要一个列表list<Control*> ,并将您喜欢的任何Control派生对象放入其中。

I hate to tell you but if you're using a list of instances to Control instead of pointers to Control, your buttons will be garbage anyway (Google "object slicing"). 我不想告诉你,但是如果你使用Control实例列表而不是指向Control的指针,你的按钮无论如何都会是垃圾(Google“对象切片”)。 If they're lists of pointers, then either make the list<button*> into list<control*> as others have suggested, or do a copy to a new list<control*> from the list<button*> and pass that into the function instead. 如果他们是指针列表,然后可以使list<button*>list<control*>正如其他人的建议,或做一个拷贝到一个新的list<control*>list<button*> 传递进入功能而不是。 Or rewrite the function as a template. 或者将该功能重写为模板。

So if you previously had a function called doSomething that took a list of controls as an argument, you'd rewrite it as: 因此,如果您之前有一个名为doS​​omething的函数,它将控件列表作为参数,那么您将其重写为:

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 <Button>,使用List <Control *>,它们指向Buttons。这样,您的函数只需要采用一种类型:List <Control *>。

Generally, the C++ way to write algorithms that perform on a list, sequence, ... is to provide iterators as arguments. 通常,编写在列表,序列,...上执行的算法的C ++方法是提供迭代器作为参数。

template < class iterator >
doSomething(iterator beg, iterator end);

This solves the List< Button* > is not derived from List< Control* >. 这解决了List <Button *>不是从List <Control *>派生的。 (using a template List< T* > would too, but that's kind of making your function generic-but-not-really) (使用模板List <T *>也会,但这会让你的函数变得通用 - 但不是真的)

In my experience, making good templatized functions operating on iterators can be a lot of (too much...) work, but it's the "C++ way"... 根据我的经验,在迭代器上运行良好的模板化函数可能会有很多(太多......)工作,但它是“C ++方式”......

If you go this route, consider using Boost.ConceptCheck . 如果你走这条路,考虑使用Boost.ConceptCheck It'll make your life a lot easier. 它会让你的生活更轻松。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM