Come si chiama di solito un getter non-const?

3

Molto spesso è necessario definire un getter che restituisce un riferimento a un membro e un setter corrispondente.

Di solito hanno un aspetto simile a questo:

class Foo
{
    Type member;
public:
    const Type& getVar() const { return member; }
    void setVar(const Type & value) { member = value; }
}

Tuttavia, a volte devi modificare l'oggetto Type restituito da getVar e devi ottenere un riferimento non const, quindi è necessario aggiungere un altro getter.

Come si chiama questo metodo aggiuntivo? Non ho mai visto un modo "standard" per scriverlo. C'è un modo per scriverlo in modo che quando qualcuno legge il nome, capisce che è un getter non-const?

Quello che faccio attualmente è questo:

Type & retrieveVar() { return member; }

Non sono sicuro che sia abbastanza esplicito per il lettore. Come gestisci questo problema?

    
posta Norgannon 03.07.2018 - 20:52
fonte

2 risposte

2

Per quanto riguarda la libreria standard C ++, ci sono due casi distinti, basati sulla risposta a una domanda: stai accedendo a un oggetto o manipolando la proprietà di un oggetto?

Accedere al contenuto di un contenitore è accedere a un subobject concettuale del contenitore. Questo di solito viene fatto tramite una funzione sovraccaricata che restituisce un riferimento all'oggetto. Tale riferimento sarà const o non- const in base al fatto che il contenitore sia const o meno. Questo è vero se parli di std::get<tuple> , std::optional::value o std::vector::at .

Per manipolare le proprietà di un oggetto, questo è tipicamente fatto tramite valori / parametri di ritorno. Sta ancora usando una funzione sovraccaricata; un sovraccarico non accetta affatto parametri, mentre l'altro sovraccarico assume il valore per impostare la proprietà su. Quest'ultimo non è const , e in molti casi entrambi restituiranno il valore (pre-modifica).

Gli iteratori sono un incrocio interessante. La maggior parte degli iteratori restituisce riferimenti a oggetti nei relativi contenitori. Ma la distinzione Input / OutputIterator rende possibile per gli iteratori di input generare valori che non fanno parte di un contenitore. Il loro operator* potrebbe restituire un valore piuttosto che un riferimento a un oggetto.

Allo stesso modo, gli iteratori di output hanno spesso il loro operator* per restituire un oggetto proxy che si comporta come un riferimento. Questo proxy utilizza l'operatore di assegnazione per impostare il valore nel flusso di output, senza dover restituire un valore effettivo di quel tipo.

Ma in quasi tutti i casi nella libreria standard, hai un nome di funzione con sovraccarichi multipli basato sulla const -ness dell'oggetto sorgente.

Il caso più importante dello standard che infrange questa regola è atomic::load/store , che sono funzioni denominate in modo indipendente. Uno potrebbe averli resi la stessa funzione, ma essere in grado di distinguere visivamente le operazioni di caricamento atomico dai negozi è piuttosto importante, poiché possono influire negativamente sulla funzionalità del tuo codice.

Detto questo, il C ++ nel suo complesso non ha linee guida su questo. Quanto sopra è solo come la libreria standard lo gestisce nella maggior parte dei casi. Altre librerie utilizzeranno frequentemente get/set . Alcune librerie chiameranno get ma non impostando le funzioni.

    
risposta data 04.07.2018 - 18:08
fonte
5

Non hai bisogno di due nomi di metodi, per non parlare di tre. Questo è lo stile principale utilizzato dalle classi in std :

class Thing
{
          Type & var();
    const Type & var() const;
}

Vedi ad esempio std::vector::front , std::get , qualsiasi iteratore operator* , ogni at o operator[] Posso trovare .

Esistono anche istanze di passaggio in base al valore

class Thing
{
    Type var() const;
    void var(Type);
}

Vedi ad esempio std::basic_ios::exceptions .

Molto spesso solo il "getter" sarà presente, il che rende difficile determinare cosa sia una "proprietà" e cosa sia un calcolo.

Il più vicino che ho trovato a un "classico" get_x set_x "proprietà" sono callback globali, per la gestione / ripristino degli errori globali.

Vedi std::set_new_handler , std::get_new_handler

    
risposta data 03.07.2018 - 22:30
fonte

Leggi altre domande sui tag