2010-02-22 17 views
6

El siguiente código muestra un error de compilación para void b() { m = &A::a; }; que indica que A::a() está protegido. (Lo cual es, pero eso no debería ser un problema)
Sin embargo, al compilador no le importa cuando escribo B::a(). A pesar de que ambos significan lo mismo yo preferiría A::a() porque establece explícitamente que a() se define en A.¿Por qué no es posible almacenar un puntero de función de una clase base?

Así ¿cuál es la razón por la cual se prohíbe A::a()?
EDITAR
Tal vez alguien puede encontrar un ejemplo que sería problemático si A::a() se dejó en B::b(). Si hay tal ejemplo, lo marcaré como respuesta a la pregunta.
/EDIT

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <cstdio> 

class A { 
protected: 
    void a(){ std::cout << "A::a()" << std::endl; }; 
}; 

typedef void (A::*f)(); 
class B : public A { 
public: 
    void b() { m = &A::a; }; // wont compile 
    // void b() { m = &B::a; }; // works fine 
    void c() { (this->*m)(); }; 
protected: 
    f m; 
}; 

int main(){ 
    B b; 
    b.b(); 
    b.c(); 
} 

// compile with 
// g++ -Wall main.cpp -o main 

Explicación del código:
En B que desea almacenar un puntero de función a un método en el que A sea capaz de llamar a esto más adelante en B::c(). Y sí, esto también sucede en la vida real. :-)

+0

Divertido ... sucede tanto con 'gcc-3.4.2' y' gcc-4.3.2' –

+0

puede estar relacionado para http://stackoverflow.com/questions/477829/cannot-call-base-class-protected-functions/477868#477868 – josefx

Respuesta

1

La razón debe ser similar a la razón por la que no se puede hacer esto en B sea:

class B: public A 
{ 
    //... 
    void foo(A& x) { 
     x.a(); //error 
    } 

    void foo(B& x) { 
     x.a(); //OK 
    } 
}; 

Eso protegida no significa que B puede acceder a la parte de cualquier clase, siempre es un A/derivado de A. El material protegido solo está disponible para esta y otras instancias de B.

2

Porque, de lo contrario, el mundo exterior puede encontrar este miembro protegido: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11174.

Véase también http://gcc.gnu.org/ml/gcc-patches/2004-06/msg00610.html.

+0

Hmm, en mi ignorancia todavía no puedo ver por qué es necesario El puntero a función y, por lo tanto, el método todavía está protegido en B. Entonces, no es accesible desde el exterior y si lo fuera, 'B :: b()' ¿o me falta el punto por completo? – Pascal

+0

@ tuner07, la protección de acceso está determinada por el tipo estático de la expresión. El contexto real en el que toma el puntero a la función no entra en juego. –

+0

@gf Si la protección de acceso está determinada por el tipo estático de la expresión, no debería ser posible llamar a 'A :: a()' en cualquier lugar de B. Pero eso es posible. Por lo tanto, la regla solo se aplica al caso en que una función se almacena en un puntero de función. Todavía no veo ninguna razón por la cual 'A :: a() 'deba ser prevenido por el compilador. – Pascal

0

Intenta acceder al miembro protegido a través del espacio de nombres global (A :: a es :: A :: a aquí), use B :: A :: a en su lugar.

+0

esto todavía no funciona. al menos con gcc-3.4.4. – Pascal

Cuestiones relacionadas