Полученный доступ к шаблону класса к элементам-членам базового класса
Этот вопрос является продолжением вопроса, заданного в этой теме.
Использование следующих определений классов:
template <class T>
class Foo {
public:
Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
{
/* do something for foo */
}
T Foo_T; // either a TypeA or a TypeB - TBD
foo_arg_t _foo_arg;
};
template <class T>
class Bar : public Foo<T> {
public:
Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg) // base-class initializer
{
Foo<T>::Foo_T = T(a_arg);
}
Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<T>(bar_arg)
{
Foo<T>::Foo_T = T(b_arg);
}
void BarFunc ();
};
template <class T>
void Bar<T>::BarFunc () {
std::cout << _foo_arg << std::endl; // This doesn't work - compiler error is: error: ‘_foo_arg’ was not declared in this scope
std::cout << Bar<T>::_foo_arg << std::endl; // This works!
}
При обращении к членам базового класса класса шаблона кажется, что я всегда должен явно квалифицировать членов, используя синтаксис стиля шаблона Bar<T>::_foo_arg
. Есть ли способ избежать этого? Может ли "использование" инструкции/директивы вступить в игру в методе класса шаблона для упрощения кода?
Edit:
Проблема области разрешена путем определения переменной с помощью этого синтаксиса.
Ответы
Ответ 1
Вы можете использовать this->
, чтобы пояснить, что вы обращаетесь к члену класса:
void Bar<T>::BarFunc () {
std::cout << this->_foo_arg << std::endl;
}
В качестве альтернативы вы также можете использовать "using
" в методе:
void Bar<T>::BarFunc () {
using Bar<T>::_foo_arg; // Might not work in g++, IIRC
std::cout << _foo_arg << std::endl;
}
Это дает понять компилятору, что имя участника зависит от параметров шаблона, чтобы он искал определение этого имени в правильных местах. Для получения дополнительной информации см. эту запись в С++ Faq Lite.
Ответ 2
Здесь базовый класс не является независимым базовым классом (который означает один с полным типом, который можно определить, не зная аргументов шаблона), а _foo_arg
является независимым именем. В стандартном С++ говорится, что независимые имена не просматриваются в зависимых базовых классах.
Чтобы исправить код, достаточно указать имя _foo_arg
зависимым, потому что зависимые имена могут быть просмотрены только во время создания экземпляра, и в то время будет известна точная базовая специализация, которая должна быть исследована. Например:
// solution#1
std::cout << this->_foo_arg << std::endl;
Альтернативой является введение зависимости с использованием квалифицированного имени:
// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;
Необходимо заботиться об этом решении, потому что если для формирования вызова виртуальной функции используется неквалифицированное независимое имя, тогда квалификация блокирует механизм виртуального вызова и значение программы изменяется.
И вы можете присвоить имя из зависимого базового класса в производном классе один раз using
:
// solution#3
template <class T>
class Bar : public Foo<T> {
public:
...
void BarFunc ();
private:
using Foo<T>::_foo_arg;
};
template <class T>
void Bar<T>::BarFunc () {
std::cout << _foo_arg << std::endl; // works
}
Ответ 3
Появляется, чтобы отлично работать в Visual С++ 2008. Я добавил несколько фиктивных определений для типов, о которых вы упомянули, но не дал никакого источника. Остальное точно так же, как вы выразились. Затем основная функция для принудительного создания и вызова BarFunc
.
#include <iostream>
class streamable {};
std::ostream &operator<<(std::ostream &os, streamable &s) { return os; }
class foo_arg_t : public streamable {};
class a_arg_t : public streamable {};
class b_arg_t : public streamable {};
template <class T>
class Foo {
public:
Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
{
/* do something for foo */
}
T Foo_T; // either a TypeA or a TypeB - TBD
foo_arg_t _foo_arg;
};
template <class T>
class Bar : public Foo<T> {
public:
Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg) // base-class initializer
{
Foo<T>::Foo_T = T(a_arg);
}
Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<T>(bar_arg)
{
Foo<T>::Foo_T = T(b_arg);
}
void BarFunc ();
};
template <class T>
void Bar<T>::BarFunc () {
std::cout << _foo_arg << std::endl;
std::cout << Bar<T>::_foo_arg << std::endl;
}
int main()
{
Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
b->BarFunc();
}