2012-09-04 25 views
21

Ho il seguente codice:Impossibile accedere membro protetto della classe base in classe derivata

struct A { 
protected: 
    A() {} 

    A* a; 
}; 

struct B : A { 
protected: 
    B() { b.a = &b; } 

    A b; 
}; 

E stranamente non compilazione. Il colpevole è il compito b.a = &b;: sia GCC che clang si lamentano che A() è protetto, il che non dovrebbe essere un problema perché B eredita A. Quale angolo oscuro dello standard sono entrato?

+3

È possibile accedere solo ai membri 'protetti' di' this' 'base (stessa istanza). 'this' e' b' non sono la stessa istanza. – jrok

+2

@MikeSeymour no. (ma ammetto di aver pensato la stessa identica cosa fino a poco tempo fa) –

+0

Sono sicuro che questo è stato chiesto molte volte prima, ma è difficile individuare il duplicato esatto. – dasblinkenlight

risposta

21

Il significato di protected è che il tipo derivato avrà accesso a tale membro di propria base e non di qualsiasi oggetto casuale *. Nel tuo caso, si cura cercando di modificare membro b s', che è al di fuori del vostro controllo (ad esempio è possibile impostare this->a, ma non b.a)

c'è un trucco per arrivare a questo lavoro, se siete interessati, ma un la soluzione migliore sarebbe quella di rifattorizzare il codice e non dipendere dagli hack. Si potrebbe, ad esempio, fornire un costruttore in A che prende un A* come argomento (questo costruttore dovrebbe essere pubblico) e poi inizializzare nella lista di inizializzazione dei B:

A::A(A* p) : a(p) {} 
B::B() : b(&b) {} 

*protected sovvenzioni si accede al membro di base in qualsiasi istanza del proprio tipo o derivata dal proprio tipo.

+1

+1: Sento sempre il detto "il controllo degli accessi funziona su una base per classe, non una base per oggetto ", ma sembra" protetto "è l'unica eccezione a questa regola? –

+1

@JesseGood: Non proprio, è ancora per classe. Forse ero troppo vago nella risposta. Hai accesso al membro in qualsiasi oggetto di tipo 'B' o derivato da' B', non solo in oggetti di tipo 'A' o derivati ​​da' A' (che non sono 'B') –

+0

Nota puoi anche ingannare il compilatore utilizza reinterpret_cast. Brutto, e potrebbe essere pericoloso, ma ... – Macmade

0

Tutti i compilatori che ho testato si sono lamentati di diverse cose, e in particolare il costruttore protetto sarebbe stato un problema anche se la dichiarazione di assegnazione fosse stata rimossa.

Non si accede ai membri di protected di qualsiasi istanza di un tipo derivato. Questo problema è stato chiarito negli esempi di 11.4p1.

class B { 
protected: 
    int i; 
    static int j; 
}; 

class D1 : public B { 
}; 

class D2 : public B { 
    void mem(B*, D1*); 
}; 

void D2::mem(B* pb, D1* p1) { 
    pb->i = 1; // ill-formed 
    p1->i = 2; // ill-formed 
    // ... 
} 
2

Ci sono in realtà due problemi separati qui.

Il primo è che la linea non esegue solo un compito, ma tenta di inizializzare la classe base (che funziona bene) e il membro b. Per creare il membro b è necessario costruirlo e come membro ha bisogno di public accesso a un costruttore, che non ha.

Quindi l'assegnazione non è in grado di accedere a un membro non pubblico di b perché di nuovo, non è di tipo B ma digitare A invece.

Ricordate che protected significa che è possibile accedere a parti del Aattraverso un B oggetto (o bambino) solo.

In questo caso, diteci il vostro vero problema e possiamo cercare di aiutarlo a risolverlo. Ereditare e comporre dallo stesso tipo è un odore di design.

+0

"Ereditare e comporre dallo stesso tipo è un odore di design." perché è? Puoi elaborare? Di recente ho un design e nella classe derivata ci sono diverse istanze di base (composizione). In tale scenario, ho bisogno di accedere ai membri protetti di quelle istanze di base dalle mie funzioni di classe derivate - errori di compilazione lì. Se lo specificatore di accesso protetto è per classe (piuttosto che per istanza), questo dovrebbe essere permesso - perché no? – h9uest

+0

Ciao Mark. Ho preparato una domanda specifica qui sotto, vorresti per favore prendermi un momento per illuminarmi?(Lo standard non ha detto nulla di simile a "accedere alla base attraverso un oggetto derivato"; la clausola 11 a pagina 237 afferma chiaramente che un nome protetto può essere utilizzato da classi derivate da quella classe. In altre parole, funziona su una base di classe e istanza non entra in scena.) Saluti. http://stackoverflow.com/questions/34588930/c-protected-fail-to-access-bases-protected-member-from-within-derived-class/34589641?noredirect=1#comment56950922_34589641 – h9uest

0

Sembra una grande limitazione del linguaggio C++.Come si risolve il problema in questo modo:

class Node 
{ 
public: 
void Save(); 
protected: 
virtual void SaveState(int type) = 0; 
}; 

class BinaryNode : public Node 
{ 
protected: 
Node *left; 
Node *right; 

virtual void SaveState(int type) override 
{ 
    left->SaveState(type); 
    right->SaveState(type); 
} 
}; 

In questo esempio io non voglio fare il metodo SaveState visibile Node gerarchia di fuori. Solo il metodo Save dovrebbe essere public.

+0

Se un "nodo" si nasconde i dettagli del processo di salvataggio da parte dell'utente non dovrebbero essere influenzati su di esso in "BinaryNode", perché non si conosce il tipo esatto di "Nodo *" e non si può indovinare la sua implementazione interna. In altri casi è necessario aggiungere alcuni argomenti per "Salva" per influenzarlo dall'esterno o rendere più chiaro il tuo esempio –

Problemi correlati