2009-09-24 15 views
9

È possibile eliminare error C2243?Eliminazione dell'errore C2243

class B {}; 
class D : protected B {}; 

D d; 
B *p = &d; // conversion from 'D *' to 'B &' exists, but is inaccessible 

Ho avuto questo errore nel mio app e alla fine sono riuscito a compilarlo facendo una conversione esplicita:

D d; 
B *p = (B*)&d; 

non riesco a capire il motivo per cui facendo classe D ereditato protetta da B rende inaccessibile la conversione implicita.

ho cercato di evitare la conversione esplicita con la creazione di un operatore di B() in classe D al fine di rendere la conversione accessibili:

class B {}; 
class D : protected B 
{ 
public: 
operator B() {return *this;} 
}; 

Ma non c'è modo.

Qualsiasi altra soluzione per evitare la conversione esplicita?

risposta

17

Se si desidera consentire la conversione, è necessario utilizzare l'ereditarietà pubblica.

Utilizzando l'ereditarietà protetta o privata, si dichiara che il fatto che il tipo derivato erediti dalla classe di base è un dettaglio che non dovrebbe essere visibile dall'esterno: è per questo che si sta verificando tale errore.

Si deve considerare l'eredità non pubblica solo come una forma di composizione con la possibilità aggiunta di sovrascrivere i metodi.

+0

Che dire di dare accesso solo al interfaccia const della classe base? Quindi ereditare privatamente e permettere di trasmettere a const base e? Chiedere perché non riesce a farlo funzionare su MSVC ... –

+0

Basta rispondere a me stesso, è necessario gestire la classe per aggregazione non ereditarietà, altrimenti MSVC viene confuso e tenta di risolvere la conversione per eredità privata (operatore nascosto operatore) –

8

Perché l'ereditarietà protected e private non è la relazione is-a, sono solo zucchero di sintassi per la composizione. Le tue lezioni possono essere riscritti esattamente come questo, ma si perde la comodità di lasciare che il compilatore definiscono b per voi, e con i membri B direttamente invece di riferirsi ad esso in modo esplicito:

class D 
{ 
    protected: 
    B b; 
}; 

Per il secondo punto di la tua domanda:

operator B() {return *this;} 

Questa linea ha a che fare con B e D. D * e B * sono totalmente diversi da B e D anche se sono indicatori per loro! per lanciare puntatori, si potrebbe reinterpretare il puntatore:

B *p = reinterpret_cast<B*>(&d); // TOTALLY WRONG, although it compiles :) 

Non fare la linea di cui sopra! Penso che potresti darci maggiori informazioni su ciò che stai cercando di ottenere.

2

perché fuori di D ed i bambini Ds, nessuno sa che sono padre-figlio, quindi è necessario farlo in modo esplicito.

questo è quello protetto mezzi di successione, solo la tua famiglia (bambini) saprà che si eredita. E potresti usarlo, ad esempio in un metodo per bambini, lì una conversione implicita sarebbe legale.

Se vuoi avere una conversione implicita dai tuoi figli, devi renderla pubblica per farla conoscere a tutti.

0

Hai provato a rendere l'operatore B() pubblico in classe D? Nel codice che hai mostrato, sarebbe contrassegnato come protetto e ancora inaccessibile. Ma eviterei gli operatori di conversione in generale, se possibile.

Tuttavia, l'ereditarietà di B protetta significa che si intende impedire di eseguire B * p = & d. Immaginate se B fosse in realtà una variabile membro protetta nella parte superiore di D. Proprio come non è possibile accedere a D.b in quel caso, non è possibile accedere a d come B *, a meno che non lo si passi.

Quindi, ereditate B pubblicamente o usate i vostri cast. Andrò pubblicamente B ereditando, perché ereditandolo protetto fondamentalmente dice "Non usare me come B", che stai cercando di fare comunque.

+1

facendo diventare operatore B() pubblico non funziona neanche –

2

Il problema qui è che si sta tentando di eseguire una fine corsa intorno alle informazioni nascoste che fornisce l'attributo protetto. Se desideri accedere a un'istanza di D come B, perché l'hai ereditata come protetta anziché pubblica ?. Quello che stai dicendo usando l'ereditarietà protetta è che desideri che solo le istanze di D e i suoi discendenti siano a conoscenza del componente B. Hai bisogno di guardare di nuovo a ciò che vuoi realizzare.

Il vecchio cast di stile C che si sta utilizzando non ha la sottigliezza dei più recenti cast di C++, quindi fornisce il codice che verrà compilato ma il problema è davvero nell'ereditarietà.

0

Nessuno conosce al di fuori che sono genitore-figlio, è solo possibile eseguire questa azione a D's class.This derivata è un esempio (test in Visual Studio 2013):

class BASE{}; 

class BASE1 :protected BASE{}; 

class BASE2 :protected BASE1 
{ 
public: 
    void func(BASE &a, BASE1 &b){a = b;} 
}; 

void main() 
{ 
    BASE a; 
    BASE1 b; 
    BASE2 c; 

    c.func(a, b);; 
    system("pause"); 
}