resueltos resolucion que poo operador objeto ejercicios ejemplos derivada codigo clases clase ambito c++ templates inheritance scope name-lookup

c++ - resolucion - Acceso derivado de la clase de plantilla a los datos de miembros de la clase base



operador de resolucion de ambito c++ (3)

Esta pregunta es un adelanto de la pregunta en este hilo .

Usando las siguientes definiciones de clase:

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! }

Al acceder a los miembros de la clase base de la clase de plantilla, parece que siempre debo calificar explícitamente a los miembros utilizando la sintaxis de estilo de plantilla de Bar<T>::_foo_arg . Hay alguna manera de evitar esto? ¿Puede una declaración / directiva ''using'' entrar en juego en un método de clase de plantilla para simplificar el código?

Editar:

El problema de alcance se resuelve calificando la variable con this-> sintaxis.


Aquí la clase base no es una clase base no dependiente (lo que significa que tiene un tipo completo que puede determinarse sin conocer los argumentos de la plantilla), y _foo_arg es un nombre no dependiente. El estándar C ++ dice que los nombres no dependientes no se buscan en clases base dependientes.

Para corregir el código, basta con hacer que el nombre _foo_arg dependiente porque los nombres dependientes solo se pueden buscar en el momento de la instanciación, y en ese momento se conocerá la especialización base exacta que se debe explorar. Por ejemplo:

// solution#1 std::cout << this->_foo_arg << std::endl;

Una alternativa consiste en introducir una dependencia utilizando un nombre calificado:

// solution#2 std::cout << Foo<T>::_foo_arg << std::endl;

Se debe tener cuidado con esta solución, ya que si el nombre no dependiente no calificado se usa para formar una llamada de función virtual, la calificación inhibe el mecanismo de llamada virtual y cambia el significado del programa.

Y puede traer un nombre de una clase base dependiente en la clase derivada una vez 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 funcionar bien en Visual C ++ 2008. Agregué algunas definiciones ficticias para los tipos que mencionas pero no proporcioné ninguna fuente. El resto es exactamente como lo pones. Luego, una función principal para obligar a BarFunc a ser instanciado y llamado.

#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(); }


Puede usar this-> para aclarar que se refiere a un miembro de la clase:

void Bar<T>::BarFunc () { std::cout << this->_foo_arg << std::endl; }

Alternativamente, también puede usar " using " en el método:

void Bar<T>::BarFunc () { using Bar<T>::_foo_arg; // Might not work in g++, IIRC std::cout << _foo_arg << std::endl; }

Esto deja en claro para el compilador que el nombre del miembro depende de los parámetros de la plantilla para que busque la definición de ese nombre en los lugares correctos. Para obtener más información, también vea esta entrada en C ++ Faq Lite .