2012-11-27 13 views
12

Di solito quando si dispone di una variabile membro privata costante nella tua classe, che ha solo un getter, ma non setter, sarebbe simile a questa:C++ che definisce una variabile membro costante all'interno costruttore della classe

// Example.h 
class Example { 
    public: 
     Example(const int value); 
     const int getValue() const; 
    private: 
     const int m_value; 
}; 


// Example.cpp 
#include "Example.h" 

Example::Example(const int value) 
: m_value(value) 
{ 
} 

const int Example::getValue() const 
{ 
    return m_value; 
} 

Ora che cosa Sto cercando di fare, è avere una variabile membro int costante come quella, ma invece di definirla nella sezione di inizializzazione in questo modo: : m_value(value) Ho bisogno di prendere un altro oggetto - userò un vettore in questo esempio - come parametro del costruttore e impostare m_value in base all'oggetto parametro. In questo caso, cercherò di fare il formato del vettore + 1, se la dimensione è superiore a 0. Quindi questo è quello che ho fatto:

Example::Example(std::vector<Example*> myVec) 
{ 
    if (myVec.size()) { 
     m_value = myVec.size() + 1; 
    } 
    else { 
     m_value = -1; 
    } 
} 

ma ottengo un errore uninitialized member 'Example::m_value' with 'const' type 'const int' e se m_value io init all'interno di inizializzazione sezione, ottengo l'errore assignment of read-only data-member 'Example::m_value' che tutto ha senso per me, dovrei ottenere quegli errori, ma come potrei aggirarli?

Modifica: L'unico modo per modificare m_value è all'interno dell'oggetto stesso (poiché m_value è privato). Avere solo getter mi limiterebbe dall'impostare m_value a qualcosa di diverso da ciò che è impostato nel costruttore. Traggo beneficio dall'avere costante int come variabile membro?

+1

': valore_m (! MyVec.empty()? MyVec.size() + 1: -1)'? – hmjd

+0

perché deve essere 'const'? – Nim

+0

Per quanto riguarda il vostro aggiornamento - no, nessun vantaggio che posso vedere ... – Nim

risposta

22

Utilizzare una funzione membro statica per calcolare il risultato desiderato e chiamare tale funzione nell'elenco di inizializzazione. Come questo:

// Example.h 
class Example { 
    public: 
     Example(const int value); 
     Example::Example(std::vector<Example*> myVec); 

     const int getValue() const; 
    private: 
     const int m_value; 

     static int compute_m_value(::std::vector<Example*> &myVec); 
}; 

// Example.cpp 
#include "Example.h" 

Example::Example(const int value) 
: m_value(value) 
{ 
} 

Example::Example(std::vector<Example*> myVec) 
: m_value(compute_m_value(myVec) 
{ 
} 

const int Example::getValue() const 
{ 
    return m_value; 
} 

int Example::compute_m_value(::std::vector<Example*> &myVec) 
{ 
    if (myVec.size()) { 
     return myVec.size() + 1; 
    } 
    else { 
     return -1; 
    } 
} 

In questo caso particolare, la funzione è quindi molto semplice, si può semplicemente utilizzare l'operatore ternario (aka : m_value(myVec.size() > 0 ? myVec.size() + 1 : -1) nel costruttore per calcolare direttamente il valore in fase di inizializzazione. Questo mi è sembrato un esempio, quindi ti ho dato un metodo molto generale per risolvere il problema, anche quando il metodo di calcolo della risposta di cui hai bisogno potrebbe essere molto complesso.

Il problema generale è che le variabili membro costanti (e le variabili membro che fanno riferimento anche a BTW) devono essere inizializzate nella lista di inizializzazione. Ma gli inizializzatori possono essere espressioni, il che significa che possono chiamare funzioni. Poiché questo codice di inizializzazione è piuttosto specifico per la classe, dovrebbe essere una funzione privata (o forse protetta) alla classe. Ma, poiché è chiamato per creare un valore prima che la classe sia costruita, non può dipendere da un'istanza di classe, quindi nessun puntatore this. Ciò significa che deve essere una funzione membro statico.

+1

+1 per risolvere il problema generale e la spiegazione chiara. – undu

5

Innanzitutto, la variabile è definita nella definizione della classe, non nel costruttore. È inizializzato nel costruttore.

In secondo luogo, il modo per farlo è proprio come quello che il vostro costruttore attualmente non: memorizzare il valore in esso dalla lista di inizializzazione:

Example::Example(std::vector<Example*> myVec) 
    : m_value(myVec.size() ? myVec.size() + 1 : -1) { 
} 
+1

Questo risolve il problema nel caso molto stretto di questo esempio. Che dire se il codice per calcolare l'inizializzatore è significativamente più complesso di quello che riesci a inserire in un'espressione? – Omnifarious

+1

@Onfarious - vedi la risposta data da Omnifarious. –

+0

@Onniversario: poi scrivi un piccolo aiuto di funzione che lo fa –

0

Sono disponibili due opzioni di base. Uno è quello di utilizzare l'operatore condizionale, che va bene per semplici condizioni come la vostra:

Example::Example(const std::vector<Example*> &myVec) 
    : m_value(myVec.size() ? myVec.size() + 1 : -1) 
{} 

per cose più complesse, è possibile delegare il calcolo di una funzione membro. Fare attenzione a non chiamare funzioni membro virtuali al suo interno, come verrà chiamato durante la costruzione.E 'più sicuro per rendere static:

class Example 
{ 
    Example(const std::vector<Example*> &myVec) 
    : m_value(initialValue(myVec)) 
    {} 

    static int initialValue(const std::vector<Example*> &myVec) 
    { 
    if (myVec.size()) { 
     return myVec.size() + 1; 
    } else { 
     return -1; 
    } 
    } 
}; 

Quest'ultimo funziona con definizioni out-of-class, nonché, naturalmente. Li ho posizionati in classe per risparmiare spazio nella scrittura &.

Problemi correlati