Наследование шаблонного класса
От: Кузнец Россия  
Дата: 11.10.16 12:15
Оценка:
Есть такая простая иерархия шаблонных классов

template<class T>
class A
{
protected:
    void FooA() {}
}

template<class T>
class B : public A<T>
{
    void FooB()
    {
        FooA();   // Ошибка компиляции
        A<T>::FooA();   // А тут ошибки компиляции нет
    }
}


Вызов функции FooA() недоступен из унаследованного класса, будет ошибка компиляции типа "Функция FooA() должна быть объявлена в прямой области видимости" (компилятор GNU, в студии такое может и пройдёт). Обращение к ней приходится делать через непосредственное указание базового класса: A<T>::FooA(), что не очень удобно. Можно залатать это, добавив в класс B строку:

...
using A<T>::FooA;
...


То же самое относится и к полям класса, не только к функциям.

Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?
Re: Наследование шаблонного класса
От: Chorkov Россия  
Дата: 11.10.16 12:21
Оценка:
Здравствуйте, Кузнец, Вы писали:

К>Есть такая простая иерархия шаблонных классов




К>Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?


пользуюсь таким приемом:
template<class T>
class B : public A<T>
{
    typedef A<T> base;
    void FooB()
    {
        base::FooA();
    }
}


Популярная альтернатива:
template<class T>
class B : public A<T>
{
    void FooB()
    {
        this->FooA();
    }
}
Re: Наследование шаблонного класса
От: Кодт Россия  
Дата: 11.10.16 13:35
Оценка: 2 (1)
Здравствуйте, Кузнец, Вы писали:

К>Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?


Это связано с тем, что FooA является зависимым именем (точнее, — мы-то знаем, что оно является зависимым именем), поэтому компилятору нужно чётко намекнуть, где его искать.
Либо писать this-> для членов экземпляра класса, либо SelfClass:: или BaseClass:: для статических членов.

Чтобы понять логику компилятора, — представь себе, что твой базовый класс имеет специализации
struct Base {
  int var;
};

template<class T> struct A {};

template<class T> struct A<T*> : Base {
  void foo() {}
  static void xyz() {}
};

template<> struct A<int> {
  void bar();
};

template<class T> struct B : A<T> {
  void go() { foo(); var; xyz(); }  // как догадаться, что надо лезть в A<T*>? в Base?
};

Явное обозначение зависимости — т.е. операторы :: . -> — заставят компилятор успокоиться и отложить вопросы доступности/уместности имени до момента инстанцирования шаблона.
Перекуём баги на фичи!
Re[2]: Наследование шаблонного класса
От: Кодт Россия  
Дата: 11.10.16 13:36
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>пользуюсь таким приемом:


можно даже так:
C>
C>template<class T>
C>class B : public A<T>
C>{
      typedef B self;
C>    void FooB()
C>    {
          self::FooA();
C>    }
C>}
C>
Перекуём баги на фичи!
Re: Наследование шаблонного класса
От: drewet Нигерия  
Дата: 11.10.16 15:39
Оценка: +1
Здравствуйте, Кузнец, Вы писали:


К>Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?


см. Standard C++
3.4.3 Qualified name lookup
Разрешение имен в зависимом от параметров шаблона контексте откладывается до момента инстанциирования, в независимом делается сразу.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.