2014-08-29 9 views
5

Mi chiedevo come proteggere un membro puntatore non const da un oggetto attraverso un metodo const. Per esempio:Metodo const C++ su membro puntatore non const

class B{ 
    public: 
     B(){ 
      this->val=0; 
     } 

     void setVal(){ 
      this->val = 2; 
     } 

    private: 
     int val; 
}; 

class A{ 
    public: 
     A():b(new B){} 
     void changeMemberFromConstMethod() const{ 
      this->b->setVal(); 
     } 
    private: 
     B * b; // how to protect data pointed in A::changeMemberFromConstMethod 
} 

E 'possibile "proteggere" A :: b dati hanno sottolineato dal suo metodo? Dopo molte ricerche sul web, nessuna risposta soddisfatta trovata ancora.

Grazie per il vostro aiuto.

+6

'" Dottore, fa male quando lo faccio "-" Quindi non farlo ". 'Non è come se qualcuno ti torceva il braccio e ti costringe a chiamare' setVal' da un metodo const. Suppongo di non capire la natura del problema. –

+0

È solo ad esempio lo scopo. Ad esempio è come una garanzia che voglio impostare non modificare i dati B puntati. – Alex

+0

Se non si desidera modificare '* b', basta non farlo. Non riesco ancora a cogliere la natura della difficoltà. –

risposta

10

Qualcosa di simile, forse:

template <typename T> 
class deep_const_ptr { 
    T* p_; 
public: 
    deep_const_ptr(T* p) : p_(p); 

    T* operator->() { return p_;} 
    const T* operator->() const { return p_;} 
}; 

class A { 
    deep_const_ptr<B> b = new B; 
}; 

deep_const_ptr si comporta come un puntatore const T* const nei metodi const A s', e come T* a metodi non-const. Sparire ulteriormente la classe è lasciato come esercizio per il lettore.

+1

+1 Bella soluzione. –

+0

È interessante! Ma come viene scelto l'operatore giusto? – Alex

+2

Con il sovraccarico di reso, ovviamente. In che altro modo? –

6

Se si modifica il membro del A da

B* b; 

a

B b; 

allora si otterrà il comportamento previsto.

class A{ 
    public: 
     A() : b() {} 

     void changeMemberFromConstMethod() const{ 
      this->b.setVal(); // This will produce a compiler error. 
     } 
    private: 
     B b; 
} 
+1

Lo so. Grazie – Alex

4

Il problema che ho è che un metodo const rende tutte le variabili membro const. In questo caso, tuttavia, rende il puntatore const. In particolare, è come se tutto quello che hai è B * const b, che significa un puntatore costante a un (ancora) mutabile B. Se non si dichiara la variabile membro come const B * b, (ovvero, un puntatore mutabile a una costante B), non c'è modo di proteggere da questo comportamento.

Se tutto ciò che serve è un const B, poi con tutti i mezzi, definire A come questo:

class A { 
public: 
    A() : b(new B) {} 

    // This WILL give an error now. 
    void changeMemberFromConstMethod() const { b->setVal(); } 
private: 
    const B* b; 
} 

Tuttavia, se altri metodi di A mutare B, allora tutto si può fare è fare in modo che B fa non viene modificato nei metodi const di A.

+0

Sono d'accordo con te. Ma se imposto: void changeMemberFromConstMethod() {b-> setVal();} Questo fallirà nell'altra mano. Mi piacerebbe che il metodo const dicesse: const B * b const; vedi ? – Alex

1

Provare a utilizzare il seguente approccio generale, per proteggere la costanza degli oggetti referenziati tramite i puntatori, in questa situazione.

  1. Rinomina B * b

    B *my_pointer_to_b; 
    

    E cambiare l'inizializzazione nel costruttore di conseguenza.

  2. implementare due stub:

    B *my_b() { return b; } 
    const B *my_b() const { return b; } 
    
  3. sostituire tutti i riferimenti esistenti per B con my_b(), nel codice esistente. Andando avanti, in qualsiasi nuovo codice, usa sempre my_b() per restituire il puntatore a b.

I metodi mutabili otterranno un puntatore non-const a B; i metodi const ottengono un puntatore const su B, e il passaggio extra del renaming fa in modo che tutto il codice esistente sia forzato a rispettare il nuovo regime.

+0

È un approccio interessante. Ma è un po 'contorto ^^. Com'è possibile che venga trovato il metodo giusto in base al metodo const o no? – Alex

+1

Un metodo const può solo richiamare altri metodi const. In un metodo const, "questo" è un puntatore costante, non un puntatore mutevole. Questo è davvero un modello di progettazione abbastanza comune. –

+0

Grazie per la tua luce – Alex