Вызов метода супер шаблонного класса без знания типа шаблона в C ++ - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть базовый класс, который использует шаблон, и у него есть несколько методов, которые не зависят от типа шаблона, но когда я использую указатель Base* a вместо производного класса, компилятор жалуется, потому что тип не указан,Я знаю, что в Java это возможно, но не уверен, что это возможно в C ++.Вот простой пример:

template <typename T>
class Base {
public:
    Base(const T& t) : _t(t) {}
    virtual ~Base() { }

    void doSomething() { std::cout << "Hello world/n"; }

    virtual T getVal() const { return _t; }

private:
    T _t;
};

class DerivedA : public virtual Base<std::string>
{
public:
    DerivedA(const std::string& path) : Base<std::string>(path) {}
    virtual ~DerivedA() {}
};

class DerivedB : public virtual Base<int>
{
public:
    DerivedB(int value) : Base<int>(value) {}
    virtual ~DerivedB() {}
};

int main(int argc, const char * argv[]) {

    DerivedA d("hello world\n");
    Base* basePtr = &d; // ERROR: Use of class template 'Base' requires template arguments
    basePtr->doSomething();

Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 26 сентября 2018

Обобщения в Java - это нечто совершенно отличное от шаблонов в C ++.Обобщения основаны на стирании типов, в то время как с шаблонами каждый экземпляр является отдельным типом, совершенно не связанным с другим экземпляром.

Т.е. в Java ArrayList<Integer> - это то же самое, что и ArrayList<Boolean>.С другой стороны, с шаблонами Base<int> не имеет отношения к Base<std::string> (кроме двух типов, являющихся результатом одного и того же шаблона), и, следовательно, ваши производные классы на самом деле не имеют общий базовый класс.

Чтобы решить вашу проблему, вы можете написать (не шаблонный) базовый класс, который объявляет общий интерфейс всех ваших производных классов.

0 голосов
/ 26 сентября 2018

Давайте 1 st поговорим о простом решении вашей проблемы, написав функцию деривации:

template<typename T>
Base<T>* make_base(Base<T>* param) {
    return param;
}

Вы можете использовать это следующим образом:

DerivedA d("hello world\n");
auto basePtr = make_base(&d);

basePtr->doSomething();

Это решение может быть улучшено, как в в этом примере , но так как я не думаю, что это лучшее решение, я не буду загромождать ответ, нооставьте такую ​​оптимизацию на ваше усмотрение.

Но 2 и давайте поговорим об улучшении вашего дизайна.Вы заметите, что любой из стандартных контейнеров создает using value_type = ..., тем самым сохраняя типы шаблонов, которые они передали.Это важно для этой точной ситуации !Если вы публично добавите using value_type = T в свой шаблонный класс Base, вы обойдете проблему, с которой вы все вместе, без необходимости make_base вы сможете сделать:

Base<decltype(d)::value_type>* basePtr = &d;

Важной концепцией продолжения здесь является то, что DerivedA и DerivedB do не имеют одинаковый базовый класс.Таким образом, вы никогда не сможете сделать что-то подобное

auto basePtr = make_base(&d);
basePtr = new DerivedB({});

0 голосов
/ 26 сентября 2018

Просто создайте другой базовый класс, который не является шаблоном:

class ReallyBase {
public:
    virtual ~ReallyBase() = default;
    void doSomething() { std::cout << "Hello world\n"; }
};

template <typename T>
class Base : public ReallyBase {
public:
    Base(const T& t) : _t(t) {}
    virtual const T& getVal() const { return _t; }    
private:
    T _t;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...