2016-06-28 18 views
6

vorrei ereditare da una classe con il const identificatore in questo modo:Eredita dalla classe const

class Property 
{ 
    int get() const; 
    void set(int a); 
}; 

class ConstChild : public const Property 
{ 
    // Can never call A::set() with this class, even if 
    // the instantiation of this class is not const 
}; 

class NonConstChild : public Property 
{ 
    // Can call both A::set() and A::get() depending on 
    // the constness of instantiation of this class 
}; 

mio compilatore mi dà evidentemente un errore per la parola chiave const nella seconda dichiarazione di classi. Idealmente, vorrei evitare di dover creare una nuova classe ReadOnlyProperty da cui ereditare ConstChild.

Posso in qualche modo utilizzare la parola chiave const per l'ereditarietà?

  • In caso contrario, avete altre idee su come risolvere questo problema?
+0

Si potrebbe dotare 'ConstChild' con un metodo factory come l'unico modo per costruisci le istanze rendendo il costruttore 'private'. Se restituisce i riferimenti 'const', verrai lì. –

+3

Utilizzare l'aggregazione sull'ereditarietà. –

+0

@ thomas-b-preusser Il punto di questo è di abilitare 'ConstChild' ad avere i metodi' const' e non 'const', cioè devono avere istanze di quella classe che sono costanti e non-costanti, mentre ' La proprietà di quella classe sarà sempre costante, cioè il metodo 'set' non può mai essere chiamato su di esso. –

risposta

2

vorrei ereditare da una classe con l'identificatore const"

Per quanto si desidera è irrilevante. Non è possibile. Questo non è valida C++.

Posso in qualche modo usare la parola chiave const per l'ereditarietà? "

No.

+1

Qualche idea sul secondo tempo, "Se no, hai qualche altra idea su come risolvere questo problema?" –

0

Se si crea una funzione const membro set, otterrete quello che vi serve.

class Property 
{ 
    int get() const; 
    void set(int a); 
}; 

class ConstChild : public Property 
{ 
    void set(int a) const {} 
}; 

L'unica avvertenza è che un utente malizioso può aggirare la vostra intenzione utilizzando:

ConstChild child; 
child.set(10); // Not OK by the compiler 

Property& base = child; 
base.set(10); // OK by the compiler 
+1

e se il 'void set (int a)' è stato dichiarato come 'virtuale'? – Mike

+0

Inoltre, oltre a quanto banale è lavorare, questo risponde solo alla domanda se l'OP "Non può mai chiamare" A :: set() "in realtà significa" può chiamarlo, ma senza che succeda nulla "... che dubito. Si potrebbe pensare che significhi sinceramente che non possa essere chiamato, cioè genererebbe un errore di compilazione, come qualsiasi tentativo di chiamare un metodo non-'' '' 'nel tipo di oggetto' const' reale a cui hanno disegnato un'analogia. –

+1

Quando l'istanza di 'ConstChild' è' const' stessa, potrei chiamare il suo metodo 'set', il che farebbe sembrare che stia effettivamente facendo qualcosa, cosa che non lo è. Idealmente la riga 'Property & base = child;' causerebbe un errore del compilatore, dal momento che cerca di scartare 'const'ness. –

4

Introdurre mutevolezza più avanti nel vostro albero di eredità e ricavare in modo appropriato:

class Property 
{ 
    int get() const; 
}; 
class MutableProperty : public Property { 
{ 
    void set(int a); 
}; 

E poi:

class ConstChild : public Property { ... }; 
class MutableChild : public MutableProperty { ... }; 
+1

Mi rendo conto che questa è una soluzione al problema stesso, anche se ho specificato che preferirei non creare una classe separata 'ReadOnlyProperty', che è esattamente ciò che è, solo con nomi diversi. –

+0

Concessione - anche se la tua denominazione sarebbe stata davvero indesiderabile come una 'Proprietà 'sarebbe anche una' ReadOnlyProperty' pur non essendo read-only.Infine, temo che tu stia veramente chiedendo una nuova funzione linguistica allora. E non è irragionevole immaginare tutti i modificatori che permetteranno ai membri regolari di andare anche con le superclassi. –

0

Utilizzare un membro dati o una classe base privata invece della classe base pubblica.

Quindi si controlla l'accesso a quel membro.

È possibile impostare la proprietà come un'interfaccia astratta se si desidera un comportamento polimorfico.

0

Ho un trucco, non una soluzione pulita.

class ConstChild : private Property 
{ 
    operator const Property() { return *this; } 
}; 

poi

ConstChild cc; 
cc.set(10); // ERROR 
cc().get(); 
+0

Questo non è corretto su molti livelli, in primo luogo l'operatore di conversione non sarà mai chiamato come gcc avverte 'warning: conversione della funzione convertendo 'ConstChild' nella sua classe base 'Proprietà' non sarà mai usata '. Quindi ConstChild non fornisce 'operator()', quindi 'cc()' non è valido. Presumibilmente 'cc.operator const Property(). get() 'sarebbe, nel qual caso' operator const Property & 'avrebbe più senso. An anche allora la sintassi è brutta. L'unico pensiero che avrebbe senso è dichiarare 'using Property :: get' in' ConstChild'. – alfC

0

È possibile utilizzare una classe template e una specializzazione per un tipo di costante:

template<typename T> class base_property { 
    protected: 
     T value; 
    }; 
    template<typename T> class property : public base_property<T> { 
    public: 
     const T& get()const { return value; } 
     void set(const T& v){ value = v; } 
    }; 

    template<typename T> class property<const T> : public base_property<T> { 
    public: 
     const T& get()const { return value; } 
    }; 

    class ConstChild : public property<const int>{ }; 
+0

In pratica si tratta solo di creare un'intera classe separata in primo luogo. Non proprio nello spirito di ciò che è stato chiesto! –

+0

ma risponde alla seconda domanda: "Se no, hai qualche altra idea su come risolvere questo problema?", E puoi usare una classe base per entrambi che contiene i dati –

+0

In tal caso perché preoccuparti del modello? Basta avere due classi distinte. Devi reimplementarli comunque. –

Problemi correlati