Есть такая простая иерархия шаблонных классов
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;
...
То же самое относится и к полям класса, не только к функциям.
Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?
Здравствуйте, Кузнец, Вы писали:
К>Есть такая простая иерархия шаблонных классов
К>Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?
пользуюсь таким приемом:
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();
}
}
Здравствуйте, Кузнец, Вы писали:
К>Это не очень удобно — если у базового шаблонного класса есть много методов, которые нужно дёргать из класса-потомка, то для каждого придётся добавлять по такой строчке. Есть ли способы обойти эту проблему?
Это связано с тем, что 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?
};
Явное обозначение зависимости — т.е. операторы :: . -> — заставят компилятор успокоиться и отложить вопросы доступности/уместности имени до момента инстанцирования шаблона.
Здравствуйте, 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>