una subclase servir que públicas puede protegidas privadas para otra modo hijo herencia ejemplos destructores derivadas constructores clases clase c++ c++11 templates namespaces

c++ - subclase - la herencia es un modo de



Mover una función miembro de la clase base a la clase derivada rompe el programa sin ninguna razón obvia (4)

  1. ¿Por qué pasó esto?

Para la clase derivada, B<T> no es una clase base no dependiente, no se puede determinar sin conocer el argumento de la plantilla. Y bitset es un nombre no dependiente, que no se buscará en la clase base dependiente. En cambio, std::bitset se usa aquí (debido al using namespace std; de using namespace std; ). Entonces obtendrás:

return std::bitset<32 && 63>(~n & 255) == oldmode && regex_match(s, sig_regex);

Puede hacer que el nombre dependa de bitset ; porque los nombres dependientes solo se pueden buscar en el momento de la creación de instancias, y en ese momento se conocerá la especialización de base exacta que debe explorarse. Por ejemplo:

return this->bitset < 32 // The mouth is not full of teeth // ~~~~~~ && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches

o

return B<T>::bitset < 32 // The mouth is not full of teeth // ~~~~~~ && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches

o

using B<T>::bitset; return bitset < 32 // The mouth is not full of teeth && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches

  1. ¿Cuál debería ser el título de esta pregunta después de haberla respondido?

"¿Cómo acceder a los nombres no dependientes en la clase base de plantilla?"

Esta pregunta (inventada) se formuló inicialmente como un rompecabezas, ocultando algunos de los detalles que podrían ayudar a ver el problema más rápido. Desplácese hacia abajo para MCVE versión más simple de MCVE .

Versión original (a-la puzzle)

Tengo este código que genera 0 :

#include <iostream> #include <regex> using namespace std; regex sig_regex("[0-9]+"); bool oldmode = false; template<class T> struct B { T bitset; explicit B(T flags) : bitset(flags) {} bool foo(T n, string s) { return bitset < 32 // The mouth is not full of teeth && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches } }; template<class T> struct D : B<T> { D(T flags) : B<T>(flags) {} }; int main() { D<uint64_t> d(128 | 16 | 1); cout << d.foo(7, "123") << endl; }

Sin embargo, cuando muevo la función foo() de B a D , comienza a generar 1 (la prueba está en Coliru ).

¿Por qué pasó esto?

Versión MCVE

Vive en Coliru

#include <iostream> #include <bitset> using namespace std; template<class T> struct B { T bitset{0}; bool foo(int x) { return bitset < 32 && 63 > (x + 1) == x % 2; } }; template<class T> struct D : B<T> { bool bar(int x) // This is identical to B<T>::foo() { return bitset < 32 && 63 > (x + 1) == x % 2; } }; int main() { D<uint64_t> d; cout << d.foo(1) << endl; // outputs 1 cout << d.bar(1) << endl; // outputs 0; So how is bar() different from foo()? }


Es por eso que nunca debe using namespace std;

bool foo(T n, string s) { return bitset < 32 && 63 > (~n & 255) == oldmode && regex_match(s, sig_regex); }

Ese bitset no es lo que crees que es. Debido a que B<T> es una clase base dependiente, los miembros están ocultos de la búsqueda no calificada. Por lo tanto, para acceder al conjunto de bitset , debe acceder a él a través de this 1 , o calificarlo explícitamente (consulte here para obtener más detalles):

(this->bitset) B<T>::bitset

Debido a que bitset no nombra B<T>::bitset en el caso derivado, ¿qué podría significar? Bueno, porque escribiste using namespace std; , en realidad es std::bitset , y el resto de su expresión resulta ser válido. Esto es lo que pasa:

bool foo(T n, string s) { return std::bitset<32 && 63>(~n & 255) == oldmode && regex_match(s, sig_regex); }

32 && 63 evalúa como true , que se promueve a 1u para el argumento de plantilla std::bitset . Este std::bitset se inicializa con ~n & 255 , y se verifica la igualdad con oldmode . Este último paso es válido porque std::bitset tiene un constructor no explícito que permite construir un std::bitset<1> oldmode desde el modo oldmode .

1 Tenga en cuenta que necesitamos paréntesis this->bitset en este caso debido a algunas reglas de desambiguación de análisis bastante sutiles. Consulte El miembro base dependiente de la plantilla no se resuelve correctamente para obtener más detalles.


Este es un ejemplo genial !!! :)

Creo que lo que está sucediendo es esto:

bitset < 32 && 63 >(~n & 255)

Se analiza como construirme un bitset


Sí, porque el conjunto de bitset se interpretará como un nombre no dependiente y hay una plantilla llamada std::bitset<T> , por lo tanto, se analizará como:

template<class T> struct D : B<T> { D(T flags) : B<T>(flags) {} bool foo(T n, string s) { return ((std::bitset < 32 && 63 > (~n & 255)) == oldmode) && regex_match(s, sig_regex); } };

Necesitas hacerlo así:

template<class T> struct D : B<T> { D(T flags) : B<T>(flags) {} bool foo(T n, string s) { // or return B<T>::bitset return (this->B<T>::bitset < 32) // The mouth is not full of teeth && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches } };

o mejor, no use el using namespace std;