2013-07-29 21 views
15

Posso fare questo?Posso trasmettere una classe derivata a una classe base privata, usando il cast in stile C?

class A { ... }; 

class B : private A 
{ 
    const A &foo() const 
    { 
     return *((const A *)this); 
    } 
}; 

Posso prendere una sottoclasse che eredita privatamente da una classe base e gettato a una versione pubblica della sua classe base? Posso farlo senza avere metodi virtuali?

La mia ipotesi è sì, ma volevo assicurarmi che fosse sicuro/portatile.

+0

Senza essere certi direi che è possibile, anche se ciò significherebbe sconfiggere lo scopo dell'eredità privata ... – Nbr44

+0

Direi che non sarebbe una buona cosa seguire il significato dell'eredità "privata". Questo tipo di ereditarietà significa "è implementato in termini di", mentre l'eredità pubblica è una relazione "è-a". – JBL

+0

Perché vuoi questo orribile hack in primo luogo? –

risposta

14

Sì, è possibile: §5.4/7 della norma:

... le seguenti operazioni static_cast e reinterpret_cast può essere eseguita (eventualmente seguita da un'operazione di const_cast) utilizzando la notazione cast di esplicita tipo di conversione, anche se il tipo classe base non è accessibile:

un puntatore a un oggetto di tipo classe derivata o un Ivalue di derivato tipo di classe può essere esplicitamente convertito in un puntatore o riferimento a un inequivocabile tipo di classe base, rispettivamente;

Ma cercare di non in quanto contrasta con l'obiettivo di ereditarietà privata.

+0

Ho fatto il C++ per quasi dieci anni e continuo a scoprire angoli di questa lingua. Non sono sicuro che sia un buon commento sulla lingua o su quello cattivo. Probabilmente uno cattivo. Ma hey, perché fermarsi ora. :) – AdamIerymenko

+1

In effetti ha molte curve complicate: puntatori nudi, nuovi contro nuovi [], riferimenti ciondolanti, distruttori non virtuali, std :: auto_ptr (sebbene per fortuna siano deprecati) per nominarne alcuni. Sarei persino tentato di aggiungere modelli alla lista, ma questo rischierebbe di sviare/ridicolizzare in generale! – Bathsheba

+0

Ma i modelli sono così divertenti! In realtà sono la mia parte preferita della lingua, anche se sicuramente nella categoria bazooka dell'esercito svizzero e * non sono troppo usati *. – AdamIerymenko

-5

Base sul titolo della domanda, la risposta dipende. Ma per il tuo caso nel codice sorgente, la risposta è sì.

ci sono due fattore che avrà un impatto sul answere:

  1. Se si utilizza fusione stile C, lo farà sì, perché getto chiamerà ri-interpert fusione se nessuna conversione availible. Puoi lanciare qualsiasi tipo di puntatore al tipo di puntatore di destinazione. Ma se c'è MI, il risultato potrebbe essere errato per la maggior parte dell'implementazione del linguaggio C++.

  2. Se si esegue il cast (senza cast di stile C) all'interno della funzione memeber, il risponditore sarà sì, poiché la classe base è accessibile all'interno della funzione membro. Se l'espressione si trova nella posizione in cui la classe base è inaccessibile, verrà visualizzato un errore di compilazione.

Non ci sono ulteriori dettagli su converstion standard nel C++ standard di

A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class (Clause 10) of D. 
If B is an inaccessible (Clause 11) or ambiguous (10.2) base class of D, a program that necessitates this conversion is ill-formed. 
The result of the conversion is a pointer to the base class subobject of the derived class object. The null pointer value is converted to the null pointer value of the destination type. 

Edit 2: rendere l'answere più in dettaglio.

+2

Questo non è corretto; per favore leggi le altre risposte. – Bathsheba

+4

Il paragrafo che hai citato riguarda la conversione del tipo * implicito *. Afferma che se la classe base non è accessibile, non si può convertire ad essa un puntatore di classe derivata. All'interno della classe derivata, la classe base è accessibile, quindi questo non si applica. Inoltre, c'è una regola speciale per il cast in stile C, vedi [Bathsheba] (http://stackoverflow.com/users/2380830/bathsheba) 's [risposta] (http://stackoverflow.com/a/17925216/ 420.683). – dyp

+0

"Se usi il cast di stile C, sì, perché il cast chiamerà il cast reinterpert se non sarà disponibile alcuna conversione." No, in questo caso il cast in stile C funzionerà in modo simile a un 'static_cast' tramite la regola speciale citata da Bathsheba (cioè ignorando che la classe base è inaccessibile). Dovresti usare '>' o il pulsante di quotazione per inserire virgolette, non quattro spazi o il pulsante codice. – dyp

8

Sì, è esplicitamente consentito. Alexandrescu utilizza questa ampiamente nella Modern C++ Design per il suo approccio di progettazione basato su policy:

template <typename Policy> 
class foo : Policy 
{ 
    public: 
     void do_something() 
     { 
      Policy & p = *this; 
      p.do_something(); 
     } 
}; 

Così, mentre i casi d'uso possono essere limitate, ci sono alcuni là fuori.

+4

Ma questo non è un cast in stile c vero? È solo un cast implicito per una base privata all'interno della classe. Mi sto perdendo qualcosa? – unkulunkulu

+0

I cast impliciti sono più limitati dei cast di stile c. – nijansen

+0

L'esempio di codice nella risposta non ha alcun cast in stile C, né alcun codice in cui la classe di base 'Policy' non è accessibile. Quindi non sembra pertinente a nulla che il PO stesse chiedendo. – Quuxplusone

Problemi correlati