2012-12-26 9 views
10

Ho creato una classe con due metodi get, uno const e uno non-const. Il metodo const è pubblico, quindi gli utenti possono interrogare il vettore. Il metodo non-const è protetto, quindi posso usarlo per modificare i dati di cui ho bisogno.Perché il cast di C++ non viene eseguito su const quando un metodo const è pubblico e quello non const è protetto?

Quando si tenta di utilizzare la classe, tuttavia, e chiamare il metodo get, il compilatore si lamenta che il metodo non-const è protetto. Invece, devo usare const_cast per trasmettere l'oggetto a const, quindi posso ottenere il metodo pubblico.

C'è un modo per risolvere questo? Perché il compilatore non dovrebbe eseguire il cast stesso, poiché esiste un metodo pubblico? Se rimuovo la versione protetta e lascio semplicemente quella const, funziona bene, quindi fa il cast in questa situazione. Il casting su const è sempre sicuro. Sta rimuovendo la costanza che è un problema.

risposta

3

Il compilatore considera accessibilità dopo decide quale funzione membro desidera chiamare. Cioè, le funzioni protette e private sono ancora visibili, anche se non sono accessibili.

Perché? Una ragione è che se rendeste le funzioni inaccessibili ignorate dalla risoluzione di sovraccarico, puoi cambiare la funzione che viene chiamata semplicemente cambiando la sua accessibilità. Con le regole attuali, puoi solo causare la compilazione del codice di compilazione, o causare la compilazione del codice che attualmente non funziona, o modificare qualcosa senza alcun effetto sul significato del codice. Non è possibile modificare gli specificatori di accesso e provocare silenziosamente una funzione diversa da chiamare.

Come esempio forzato, ecco una abbastanza terribile interfaccia di classe:

public: 
    // Returns the amount of change tendered for this transaction. 
    MoneyAmount change() const; 

private: 
    // Account for a change of currency. Charges standard moneychanger's fee. 
    MoneyAmount change(Currency toCurrency = Currency::USD); 

Se le funzioni non accessibili sono stati rimossi dalla risoluzione di sovraccarico, codice cliente potrebbe chiamare change() bene. E se successivamente la seconda funzione change(Currency) è stata resa pubblica e il primo eliminato, quel codice chiamerebbe improvvisamente un'altra funzione con uno scopo completamente diverso. Le attuali regole impediscono a un cambio di identificatore di accesso di modificare il comportamento di un programma di compilazione.

0

In C++, la selezione del metodo (risoluzione di sovraccarico) si verifica prima di considerare il controllo di accesso pubblico/privato.

0

Utilizzare invece un metodo setter protetto (o membro dati) anziché il metodo getter non const.

Non fa differenza se si dispone di s.th. come

class A { 
    SomeType foo_; 
protected: 
    SomeType& foo() { return foo_; } 

public: 
    const SomeType& foo() const { return foo_; } 
}; 

o

class A { 
protected: 
    SomeType foo_; 

public: 
    const SomeType& foo() const { return foo_; } 
}; 
6

di controllo di accesso membro è l'ultima cosa che si verifica quando si chiama una funzione di membro. Succede dopo la ricerca del nome, deduzione argomento template, risoluzione overload e così via. Il motivo per cui viene eseguito per ultimo è perché è stato deciso che la modifica del controllo di accesso per un membro non dovrebbe cambiare improvvisamente l'esecuzione del codice client.

Immaginate che l'accesso sia stato controllato prima della risoluzione del sovraccarico e che avete usato una libreria e una certa funzione membro in quella libreria. Quindi gli autori della biblioteca hanno reso la funzione privata. Improvvisamente, il tuo codice inizia a utilizzare un sovraccarico diverso e si comporta in un modo completamente diverso. Gli autori delle librerie probabilmente intendevano che chiunque usasse quel sovraccarico della funzione avrebbe dovuto smettere di usarlo, ma non intendevano cambiare il codice di tutti. Tuttavia, poiché lo standard è effettivamente definito, il tuo codice inizierà ora a darti un errore nell'usare un membro privato, piuttosto che comportarsi diversamente.

La soluzione è semplicemente cambiare il nome della funzione membro protetta in modo che non venga considerata.

0

Questo è il comportamento della natura del C++, se il codice del chiamante l'oggetto della classe è non-const, quindi la non-conversione, che è definita come protetta. È necessario definire l'oggetto di classe come const o utilizzare il comando const-cast sull'oggetto della classe, per cui verrà chiamata la versione const del metodo.

#include <iostream> 
class Foo { 
    public: 
     const void bar() const { std::cout << " const version called\n";} 
    protected: 
     void bar() { std::cout << " non const version called\n";} 
}; 

int main(int argc, char** argv) 
{ 
    const Foo c; 
    c.bar(); // -> work 

    Foo c1; 
    c1.bar(); // compiler complain -> void Foo::bar() is protected 
    const_cast<const Foo&>(c1).bar(); // fine 
} 
Problemi correlati