2009-07-29 23 views
14

Sto provando a creare una classe con due metodi con lo stesso nome, utilizzati per accedere a un membro privato. Un metodo è public e const qualificato, l'altro è privato e non-const (utilizzato da una classe friend per modificare il membro tramite return-by-reference).private non const e funzione di membro pubblico const - coesistono in pace?

Sfortunatamente, sto ricevendo errori di compilazione (usando g ++ 4.3): quando si usa un oggetto non-const per chiamare il metodo, g ++ si lamenta che la versione non-const del mio metodo è privata, anche se un pubblico (const) la versione esiste

Questo sembra strano, perché se la versione privata non const non esiste, tutto si compila bene.

C'è un modo per farlo funzionare? Si compila su altri compilatori?

Grazie.

Esempio:

class A 
{ 
public: 
    A(int a = 0) : a_(a) {} 
public: 
    int a() const { return a_; } 
private: 
    int & a()  { return a_; } /* Comment this out, everything works fine */ 
    friend class B; 
private: 
    int a_; 
}; 


int main() 
{ 
    A  a1; 
    A const a2; 

    cout << a1.a() << endl; /* not fine: tries to use the non-const (private) version of a() and fails */ 
    cout << a2.a() << endl; /* fine: uses the const version of a() */ 
} 
+0

Perché questo fallire? C++ consente la conversione da non-const a const, vis a vis parametro della funzione. – jkeys

risposta

13

risoluzione sovraccarico accade prima controllo di accesso, in modo che quando si chiama il metodo su un non-const A, il membro non-const viene scelto come una migliore corrispondenza. Il compilatore fallisce a causa del controllo dell'accesso.

Non c'è modo di "fare questo lavoro", la mia raccomandazione sarebbe quella di rinominare la funzione privata. C'è bisogno di avere un accesso privato?

+0

Una classe nascosta sarebbe la mia migliore scommessa - come usare una struttura di nodo all'interno di una classe più grande. – jkeys

+0

Questo è troppo male. Sospettavo che sarebbe stato così, ma non vedo perché debba essere. Spero che qualcuno mi mostri perché deve essere, così posso riposare facilmente. La ragione per cui voglio questo comportamento è perché di solito scrivo i miei getter e setter come due versioni const/non-const dello stesso metodo, senza il prefisso "get"/"set". Per questa particolare classe, non voglio permettere a nessuna classe tranne una di usare i setter (da qui la dichiarazione della classe amica). – mmocny

+0

La funzione di sovraccarico è utile soprattutto quando le funzioni eseguono la stessa operazione logica, o simile, ma su un diverso tipo di argomento (particolarmente utile nella scrittura di codice generico nei modelli). Recuperare il valore di qualcosa è un'operazione diversa dall'ottenere un riferimento a qualcosa per aggiornarlo. Per questo motivo ha senso (almeno per me!) Dare alle funzioni nomi diversi. Penso che stai 'nuotando contro il flusso' se provi a mantenere gli stessi nomi. –

2

selezionerà solo la versione const se l'oggetto viene dichiarato è const, altrimenti selezionare la versione non const (anche se questo si traduce in un errore).

Questo dovrebbe funzionare:

cout << ((const A*)&a1)->a() << endl; 

o questo:

A const& ra1 = a1; 
cout << ra1.a() << endl; 
+1

Penso che preferirei 'const_cast (a1) .a()'. Sembrerebbe un po 'più sicuro –

+0

Sì, questo è il migliore modo di farlo se hai intenzione di utilizzare un cast. Non penso che sia più sicuro del secondo metodo, tuttavia, il compilatore applicherà la sicurezza del tipo completo per l'assegnazione al riferimento. Comunque, ho pensato che avresti implementato questo, ad esempio, cambiando le firme di metodo da 'A &' a 'A const &' quando si passano queste cose in giro, piuttosto che manipolarle direttamente come in questo esempio evidentemente forzato. –

+1

Non capisco perché la risposta di Charles Bailey ha un voto più alto di questo (IMHO corretto e funzionante) risposta di Tim Sylvester che mostra l'opposto di "Non c'è modo" di fare questo lavoro "_. In realtà, sono venuto qui perché sapevo che io così Ho risolto questo problema da qualche parte nel mio codice ma ho dimenticato dove e come. (Btw. L'ho risolto esattamente come descritto sopra. Potrebbe essere, dovrei provare a google sul mio codice sorgente locale la prossima volta ...) – Scheff

Problemi correlati