2012-02-26 13 views
6

El siguiente código no compila en gcc:C++ y se inyecta nombre base

namespace One{ 
    class A{ 
    }; 
}; 

namespace Two{ 
    class A{ 
     public: 
     void what(){ 
      cout << "Two::A says what!" << endl; 
     } 
    }; 

    class B : public One::A{ 
     public: 
     B(){ 
      A xx; 
      xx.what(); 
     } 
    }; 

}; 

Y da:

gccbug.cpp: In constructor ‘Two::B::B()’: 
gccbug.cpp:23: error: ‘class One::A’ has no member named ‘what’ 

Ahora, me dijeron que este es el comportamiento correcto (debido a la base inyectada nombre de One :: A haciendo A referirse a One :: A). Sin embargo, este código se compila en C# (bueno, después de cambiar algunas cosas), por lo que parece ser específico de C++.

Lo que me pregunto es ... ¿por qué? ¿Existe un propósito específico para inyectar el nombre base "One :: A" como "A"?

+6

Solo como referencia, C#! = C++. No estoy seguro de por qué está comparando los dos –

+0

No puedo asegurarlo (no tengo mi copia en este momento), pero aparte, preguntas sobre por qué el lenguaje C++ se diseñó de la manera en que A menudo se responde en un libro llamado "El diseño y la evolución de C++" de Stroustrup. –

+0

@TonyTheLion, Bueno, es el otro lenguaje de programación tipo c que tiene "espacio de nombre", y al que tuve acceso a un compilador. No estoy diciendo que solo haya "One True Way" en el que esto sea correcto, pero esto no pareció intuitivo, al menos dado este ejemplo. – kamziro

Respuesta

3

La única razón que se me ocurre es que en C++ es probable que se mencione el nombre de la clase base en la lista de inicialización del constructor, así:

namespace Two { 

    /*...*/ 

    class B : public One::A { 
    public: 
    B():A() 
    { 
     /*...*/ 
    } 
    }; 
} 

Por supuesto, el objetivo es, pues, diferente desde el de tu ejemplo, porque en realidad declaras una variable local dentro del constructor, mientras que en mi ejemplo, el A() se refiere al objeto de tipo A que está implícito en la definición de class B debido a la herencia.

Sin embargo, la situación de mi ejemplo es más probable que ocurra, así que supongo que pensaron que no exigiríamos que el espacio de nombres se hiciera explícito en este caso. Como consecuencia, cualquier referencia a A sin un espacio de nombres se interpreta como una referencia a la clase base, en lugar de a cualquier otra clase llamada A, incluso si está en el mismo espacio de nombres que la declaración de B.

+0

Ah, sí, eso tiene sentido en realidad. Aunque digo que se siente un poco como un "truco". – kamziro

3

¿Existe un propósito específico para inyectar el nombre base "One :: A" como "A"?

Sí. Es así que se puede escribir lo siguiente:

namespace N 
{ 
    class A 
    { 
     A *a; 
    }; 
} 

En el ausencia del nombre inyectada, has de escribir N::A *a que no es agradable.

Tenga en cuenta que es a causa de nombre inyectado, se permiten las siguientes líneas:

A::A *a1; //ok 
A::A::A *a2; //ok 
A::A::A::A *a3; //ok 
A::A::A::A::A *a4; //ok 
//and so on 

Online demo

+0

¿No es esto diferente de la situación explicada por el solicitante?En el ejemplo original, "clase B" estaba dentro de un espacio de nombres, pero la clase de la que se derivaba estaba en otro. – jogojapan

+1

@jogojapan Pero 'clase B' hereda todos los nombres de su clase base, incluido el nombre inyectado de la clase base. Al estar en un ámbito interno, oculta nombres del espacio de nombres circundante. –

+0

@Bo Persson Sí. Solo estoy señalando que el ejemplo anterior no ilustra completamente este punto. En el ejemplo anterior, la única referencia a 'clase A 'está dentro del mismo espacio de nombres que la declaración de la clase misma. No necesitas una inyección de nombre para eso. – jogojapan

0

Al calificar A con One:: ha agregado el A de namespace uno en su alcance, por lo que el compilador buscará allí su resolución de nombre.

+0

Pero el objeto de tipo 'A 'declarado dentro del constructor no se ha calificado con' One :: '. Se interpreta como perteneciente a 'namespace One', aunque la declaración de' clase B' en sí misma está dentro de 'namespace Two'. – jogojapan

Cuestiones relacionadas