Добавить подклассы шаблонного базового класса в контейнер без супер-базового класса? - PullRequest
3 голосов
/ 26 февраля 2012

Я пытаюсь создать вектор (или любой контейнер STL, на самом деле), который может содержать набор различных объектов, которые являются подклассами одного определенного типа. Проблема в том, что мой базовый класс настроен по шаблону.

Из того, что я могу сказать, я должен создать интерфейс / абстрактный супер базовый класс (не уверен, что является предпочтительной терминологией C ++). Я бы предпочел не делать этого, а просто использовать мой (шаблонный) абстрактный базовый класс. Ниже приведен пример кода.

В принципе, есть ли способ не требовать WidgetInterface? Как сказать компилятору игнорировать требования шаблона? Если у меня должно быть WidgetInterface, правильно ли я иду со следующим?

#include <vector>
#include "stdio.h"

enum SomeEnum{
    LOW = 0,
    HIGH = 112358
};

// Would like to remove this WidgetInterface
class WidgetInterface{
public:
    // have to define this so we can call it while iterating
    // (would remove from Widget if ended up using this SuperWidget
    // non-template baseclass method)
    virtual void method() = 0; 
};

template <class TDataType>
class AbstractWidget : public WidgetInterface{
public:
    TDataType mData;
    virtual void method() = 0;
    // ... bunch of helper methods etc
};

class EnumWidget : public AbstractWidget<SomeEnum>{
public:
    EnumWidget(){
        mData = HIGH;
    }
    void method(){
        printf("%d\n", mData); // sprintf for simplicity
    }
};

class IntWidget : public AbstractWidget<int>{
public:
    IntWidget(){
        mData = -1;
    }
    void method(){
        printf("%d\n", mData); // sprintf for simplicity
    }
};


int main(){
    // this compiles but isn't a workable solution, not generic enough
    std::vector< AbstractWidget<int>* > widgets1; 

    // only way to do store abitary subclasses?
    std::vector<WidgetInterface*> widgets2; 
    widgets2.push_back(new EnumWidget());
    widgets2.push_back(new IntWidget());

    for(std::vector<WidgetInterface*>::iterator iter = widgets2.begin();
        iter != widgets2.end(); iter++){
        (*iter)->method();
    }

    // This is what i'd _like_ to do, without needing WidgetInterface
    // std::vector< AbstractWidget* > widgets3; 

    return 0;
}

Ответы [ 4 ]

5 голосов
/ 26 февраля 2012

Нет, вы не можете напрямую использовать AbstractWidget в качестве параметра контейнера STL или чего-либо еще.Причина в том, что класс AbstractWidget не существует .Только шаблон для компилятора может создавать классы из.

Существуют AbstractWidget<SomeEnum> и AbstractWidget<int> только потому, что EnumWidget и IntWidget наследуются от них.

Шаблоны существуют только на уровне компилятора.Если бы AbstractWidget<T> нигде не использовался в вашем коде, его бы не было никаких следов во время выполнения.

Поэтому код, который вы разместили, кажется лучшим (если неттолько) решение вашей проблемы.

0 голосов
/ 26 февраля 2012

Это может быть совсем не в том направлении, но вы можете сделать что-то вроде этого:

template <class T>
class ConcreteWidget : public AbstractWidget<T>
{
};

, а затем использовать специализацию шаблона для определения ваших конкретных виджетов, таких как:* Таким образом, вместо того, чтобы иметь IntWidget и EnumWidget, у вас были бы ConcreteWidget и ConcreteWidget, а затем вы могли бы просто иметь vector<WidgetInterface>, который был бы супер среди всех этих родовых детей?уверен, если это решит вашу проблему, или даже будет работать.Я хотел бы получить отзыв об этом ответе.

0 голосов
/ 26 февраля 2012

На самом деле классы AbstractWidget<int> и AbstractWidget<double> являются разными классами, поэтому ваш класс IntWidget является подклассом первого, но никак не связан со вторым. Вам нужно иметь общий родительский класс для вставки вектора, поэтому, к сожалению, вы не можете избежать общего интерфейса, который не является шаблонным.

0 голосов
/ 26 февраля 2012

То, что вы сделали, - это решение: вам нужен общий класс / интерфейс, и поскольку AbstractWidget является шаблоном класса, поэтому его нельзя использовать в качестве общего класса для всех конкретных классов, для которых Аргумент шаблона отличается. Поэтому я думаю, вы должны пойти с этим классом дизайна. Вроде бы вполне разумное решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...