Acesso template da classe derivada para a base de classe-membros de dados
-
13-09-2019 - |
Pergunta
Esta questão é uma promoção do único perguntou em esta discussão .
Usando as definições seguintes classes:
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!
}
Ao acessar os membros da classe base do modelo de classe, parece que eu sempre deve qualificar explicitamente os membros usando a sintaxe de estilo modelo de Bar<T>::_foo_arg
. Há alguma maneira de evitar isto? um 'usando' declaração / directiva podem entrar em jogo em um método de classe de modelo para simplificar o código?
Editar:
A questão escopo é resolvido, qualificando a variável com this-> sintaxe.
Solução
Você pode usar this->
para deixar claro que você está se referindo a um membro da classe:
void Bar<T>::BarFunc () {
std::cout << this->_foo_arg << std::endl;
}
Como alternativa, você também pode usar "using
" no método:
void Bar<T>::BarFunc () {
using Bar<T>::_foo_arg; // Might not work in g++, IIRC
std::cout << _foo_arg << std::endl;
}
Isso deixa claro para o compilador que o nome do membro depende dos parâmetros do modelo para que ele procura para a definição desse nome nos lugares certos. Para mais informações veja também esta entrada no C ++ FAQ Lite .
Outras dicas
Aqui, a classe base não é uma classe base não dependente (o que significa um com um tipo completo que pode ser determinada sem conhecer os argumentos de modelo), e _foo_arg
é um nome não dependente. Padrão C ++ diz que os nomes não dependentes não são procurados na base classes dependentes.
Para corrigir o código, basta fazer o nome _foo_arg
dependente porque os nomes dependentes podem ser consultados apenas no momento da instanciação, e naquele tempo a especialização de base exata que deve ser explorado será conhecido. Por exemplo:
// solution#1
std::cout << this->_foo_arg << std::endl;
Uma alternativa consiste na introdução de uma dependência utilizando um nome qualificado:
// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;
É preciso ter cuidado com esta solução, porque se o nome não dependente não qualificado é usado para formar uma chamada de função virtual, em seguida, os inibe de qualificação do mecanismo de chamada virtual e o significado das mudanças do programa.
E você pode trazer um nome de uma classe base dependente na classe derivada uma vez por 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
}
Parece belo trabalho no Visual C ++ 2008. Eu adicionei algumas definições fictícios para os tipos que você mencionou, mas não deu fonte. O resto é exatamente como você colocá-lo. Em seguida, uma função principal a força BarFunc
a ser instanciado e chamado.
#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();
}