Derivato accesso template classe per classe base membro-dati
-
13-09-2019 - |
Domanda
Questa domanda è un perseguimento di quello chiesto in questa discussione .
Utilizzando le definizioni di classe seguente:
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!
}
Quando si accede i membri della classe base del modello di classe, sembra che devo sempre qualificare esplicitamente i membri utilizzando la sintassi modello stile di Bar<T>::_foo_arg
. c'è un modo per evitarlo? Può un 'utilizzando' istruzione / direttiva entrare in gioco in un metodo di classe modello per semplificare il codice?
Modifica
Il problema viene risolto ambito qualificando la variabile con this-> sintassi.
Soluzione
È possibile utilizzare this->
mettere in chiaro che ci si riferisce a un membro della classe:
void Bar<T>::BarFunc () {
std::cout << this->_foo_arg << std::endl;
}
In alternativa è possibile utilizzare anche "using
" nel metodo:
void Bar<T>::BarFunc () {
using Bar<T>::_foo_arg; // Might not work in g++, IIRC
std::cout << _foo_arg << std::endl;
}
Ciò rende chiaro al compilatore che il nome del membro dipende dai parametri del modello in modo che cerca la definizione di tale nome nei posti giusti. Per ulteriori informazioni vedere anche questa voce nel C ++ Faq Lite .
Altri suggerimenti
Qui la classe base non è una classe base nondependent (il che significa che uno con un tipo completo che può essere determinato senza conoscere gli argomenti di template), e _foo_arg
è un nome nondependent. C ++ standard dice che i nomi nondependent non si vedono in classi di base a carico.
Per correggere il codice, è sufficiente fare il nome _foo_arg
dipendente perché i nomi di dipendenti possono essere consultati solo al momento di istanziazione, e in quel momento sarà noto l'esatto specializzazione di base che deve essere esplorato. Ad esempio:
// solution#1
std::cout << this->_foo_arg << std::endl;
Un'alternativa consiste nell'introduzione di una dipendenza utilizzando un nome qualificato:
// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;
Bisogna fare attenzione con questa soluzione, perché se il nome non dipendente qualificato viene utilizzato per formare una chiamata di funzione virtuale, quindi la qualificazione inibisce il meccanismo di chiamata virtuale e il significato dei cambiamenti di programma.
E si può portare un nome da una classe di base dipendente nella classe derivata da una volta 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
}
sembra funzionare bene in Visual C ++ 2008. Ho aggiunto alcune definizioni fittizi per i tipi che lei ha citato, ma dato alcuna fonte per. Il resto è esattamente come dici tu. Poi una funzione principale per costringere BarFunc
da un'istanza e chiamato.
#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();
}