Domanda

    

Questa domanda ha già una risposta qui:

         

ho a che fare con una grande base di codice che utilizza il seguente costrutto tutto

class MyClass
{
public:
  void f(int x);
private:
  int x;
};


void MyClass::f(int x)
{
'
'
  this->x = x;
'
'
}

Personalmente, ho sempre usato e quindi preferisco il modulo

class MyClass
{
public:
  void f(int x);
private:
  int _x;
};


void MyClass::f(int x)
{
'
'
  _x = x;
'
'
}

Le ragioni che preferisco quest'ultimo sono che è più succinta (meno codice = minor numero di potenziali bug), e che non mi piace avere più variabili con lo stesso nome in ambito allo stesso tempo in cui posso evitarlo. Detto questo, io sto vedendo l'ex utilizzo sempre più spesso in questi giorni. C'è qualche rialzo per secondo approccio che io sono a conoscenza di? (Ad esempio, l'effetto sul tempo di compilazione, utilizzare con il codice di template, ecc ...) sono i vantaggi di entrambi gli approcci notevole pregio sufficiente un refactoring per l'altro? Motivo che chiedo, che, mentre non mi piace il secondo approccio presente nel codice, la quantità di sforzo e il rischio associato di introdurre ulteriori bug fare il merito non proprio un refactoring.

È stato utile?

Soluzione

La versione è un po 'più pulito, ma mentre ci sei, mi sarebbe:

  1. Evitare di sottolineatura: _x è ok fino a quando qualcuno sceglie _MyField che è un nome riservato. Una sottolineatura iniziale seguito da una lettera maiuscola non è consentito come un nome di variabile. Vedi: Quali sono le regole sull'utilizzo di una sottolineatura in un identificatore C ++
  2. Fare l'attributo privato o protetto:. Il cambiamento è sicuro se si compila, e il candidato dovrà garantire verrà utilizzato il tuo setter
  3. Il this-> storia ha un impiego, ad esempio, nel codice basato su modelli per rendere il nome del campo dipende dal vostro tipo (in grado di risolvere alcuni problemi di ricerca).

Un piccolo esempio di risoluzione di nomi che sono fissati utilizzando una this- esplicito> (testato con g ++ 3.4.3):

#include <iostream>
#include <ostream>

class A
{
public:
  int g_;
  A() : g_(1) {}
  const char* f() { return __FUNCTION__; }
};

const char* f() { return __FUNCTION__; }
int g_ = -1;

template < typename Base >
struct Derived : public Base
{
  void print_conflicts()
  {
    std::cout << f() << std::endl; // Calls ::f()
    std::cout << this->f() << std::endl; // Calls A::f()
    std::cout << g_ << std::endl; // Prints global g_
    std::cout << this->g_ << std::endl; // Prints A::g_
  }
};

int main(int argc, char* argv[])
{
   Derived< A >().print_conflicts();
   return EXIT_SUCCESS;
}

Altri suggerimenti

Il campo di denominazione non ha nulla a che fare con un code smell. Come ha detto Neil , campo di visibilità è l'unico code smell qui.

Ci sono vari articoli riguardanti le convenzioni di denominazione in C ++:

ecc.

Questo utilizzo di 'questo' è incoraggiato per gli standard di codifica # Microsoft C. Dà un buon codice chiarezza, ed è destinato ad essere uno standard sopra l'uso di m_ o _ o qualsiasi altra cosa in variabili membro.

Onestamente, mi piace sottolineare nei nomi in ogni caso, ho usato per precedere tutte le mie membra da un singolo 'm'.

Un sacco di persone usano questo perché nella loro IDE farà un elenco di identificatori dell'attuale classe di pop-up.

Lo so che faccio in BCB.

Credo che l'esempio si fornisce con il conflitto di denominazione è un'eccezione. In Delphi, però, linee guida dello stile utilizzare un prefisso (solitamente "a") per i parametri per evitare esattamente questo.

La mia sensazione personale è che combattere una convenzione di codifica esistente è qualcosa che non si dovrebbe fare. Come Sutter / Alexandrescu mette nel loro libro 'C ++ convenzioni di codifica': non sudare le piccole cose. Chiunque è in grado di leggere l'uno o l'altro, se v'è un leader 'this->' o '_' o qualsiasi altra cosa.

Tuttavia, la coerenza nelle convenzioni di denominazione è qualcosa che in genere si vuole, quindi attenersi ad una convenzione ad un certo ambito (almeno nell'ambito di file, idealmente l'intera base di codice, ovviamente) è considerata buona pratica. Lei ha detto che questo stile è utilizzato in tutto una base di codice più grande, quindi penso che il retrofit un'altra convenzione sarebbe piuttosto una cattiva idea.

Se, dopo tutto, trovare v'è una buona ragione per cambiarla, non farlo manualmente. Nel migliore dei casi, il vostro IDE supporta questo tipo di 'refactoring. In caso contrario, scrivere uno script per cambiarla. Ricerca e sostituzione dovrebbe essere l'ultima opzione. In ogni caso, si dovrebbe avere una copia di backup (controllo del codice sorgente) e un qualche tipo di struttura di test automatizzati. In caso contrario, non sarà possibile divertirsi con essa.

utilizzando 'questo' in questo modo non è IMO un odore di codice, ma è semplicemente una preferenza personale. Non è quindi importante come coerenza con il resto del codice nel sistema. Se questo codice non è coerente si potrebbe cambiare in modo che corrisponda l'altro codice. Se cambiandolo si introdurrà incoerenza con la maggior parte del resto del codice, che è molto male e mi avrebbe lasciato da solo.

Se non si desidera ottenere sempre in una posizione di giocare a tennis codice dove qualcuno cambia qualcosa di puramente per far sembrare "bello" solo per qualcun altro a venire insieme più tardi con diversi gusti che poi cambia di nuovo.

Io uso sempre il m _ convenzione di denominazione. Anche se non mi piace "la notazione ungherese" in generale, lo trovo molto utile per vedere in modo molto chiaro se sto lavorando con i dati membro della classe. Inoltre, ho trovato usando 2 nomi delle variabili identici nello stesso ambito troppo incline all'errore.

Sono d'accordo. Non mi piace che la convenzione di denominazione - preferisco quella in cui v'è una distinzione evidente tra variabili e le variabili locali. Che cosa succede se si lascia fuori il this?


class MyClass{
public:  
  int x;  
  void f(int xval);
};
//
void MyClass::f(int xval){  
  x = xval;
}

A mio parere questo tende per aggiungere disordine al codice, così ho tendono ad usare diversi nomi di variabili (a seconda della convenzione, potrebbe essere una sottolineatura, m _ , a prescindere).

class MyClass
{
public:
  int m_x;
  void f(int p_x);
};


void MyClass::f(int p_x)
{
  m_x = p_x;
}

... è il mio modo preferito utilizzando prefissi di ambito. m_ per il membro, p_ per il parametro (alcuni a_ uso per la discussione invece), g_ per il mondiale e, a volte L_ per locali se aiuta la leggibilità.

Se si dispone di due variabili che meritano lo stesso nome, allora questo può aiutare molto, evita di dover fare un po 'di variazione casuale sul suo significato solo per evitare ridefinizione. O, peggio ancora, la temuta 'x2, x3, x4, ecc' ...

E 'più normale in C ++ per i membri di essere inizializzati per la costruzione utilizzando initialiser.

Per fare questo, è necessario utilizzare un nome diverso per il nome della variabile membro.

Quindi, anche se io userei Foo(int x) { this.x = x; } in Java, non lo farei in C ++.

La vera odore potrebbe essere la mancanza di uso di inizializzatori e metodi che fanno altro che mutanti variabili membro, piuttosto che l'uso del this -> x stessa.

Qualcuno sa perché è pratica universale in ogni C ++ negozio Sono stato per usare nomi diversi per argomenti del costruttore alle variabili membro quando si utilizza con inizializzatori? ci sono stati alcuni compilatori C ++ che non lo supportano?

Oggi, la maggior parte degli editori IDE colori variabili per indicare i membri della classe di variabili locali. Così, IMO, né prefissi o 'this->' dovrebbe essere richiesto per migliorare la leggibilità.

Non mi piace l'utilizzo di "questo" perché è atavica. Se stai programmando nel buon vecchio C (ricordate C?), E si vuole imitare alcune delle caratteristiche della programmazione orientata agli oggetti, si crea una struttura con diversi membri (questi sono analoghe alle proprietà del vostro oggetto) e si crea un set delle funzioni che tutti prendono un puntatore a tale struct come primo parametro (questi sono analoghi ai metodi di quell'oggetto).

(credo che questa sintassi typedef è corretto ma è stato un po '...)

typedef struct _myclass
{
   int _x;
} MyClass;

void f(MyClass this, int x)
{
   this->_x = x;
}

In realtà credo più vecchio compilatori C ++ sarebbe in realtà compilare il codice al modulo di cui sopra e poi basta passarlo al compilatore C. In altre parole - C ++ in una certa misura era solo zucchero sintattico. Quindi io non so perché qualcuno dovrebbe voler programmare in C ++ e tornare ad usare in modo esplicito "questo" nel codice - forse è "sintattico Nutrisweet"

Se hai un problema con le convenzioni di denominazione si può provare a usare qualcosa come il folowing.

class tea
{
public:
    int cup;
    int spoon;
    tea(int cups, int spoons);
};

o

class tea
{
public:
    int cup;
    int spoon;
    tea(int drink, int sugar);
};

Credo che hai avuto l'idea. E 'fondamentalmente nomi delle variabili diverse, ma "lo stesso" nel senso logico. Spero che aiuta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top