2012-10-10 9 views
5

Mögliche Duplizieren:
Members vs method arguments access in C++Konflikte zwischen den Mitgliedsnamen und Konstruktorargument Namen

Ich habe eine Klasse, die einige Mitglieder, wie x, y, width und height. In seinem Konstruktor, ich würde das nicht tun:

A::A(int x, int y, int width, int height) 
{ 
    x = x; 
    y = y; 
    width = width; 
    height = height; 
} 

Das ist wirklich nicht sinnvoll ist und wann mit g ++ kompiliert x, y, width und height werden seltsame Werte (z -1405737648).

Wie können diese Namenskonflikte optimal gelöst werden?

+3

Euh, Anhängen eines 'a' an die Argumentnamen? –

+0

'A :: A (int xa, int ya, int widtha, int höhe)' – corazza

+0

Wenn Sie elegant sein wollen, * pred * pendieren Sie das 'a' und bilden Sie einen unbestimmten englischen Artikel:' anX, aY, aWidth, aHaight' usw. Offensichtlich kann derselbe Bezeichner nicht verwendet werden, um auf zwei verschiedene Variablen im selben Bereich zu verweisen. Siehe meine Antwort. –

Antwort

17

Sie können Initialisierung Listen ganz gut mit den gleichen Namen verwenden:

A::A(int x, int y, int width, int height) : 
    x(x), 
    y(y), 
    width(width), 
    height(height) 
{ 
} 

Eine Alternative ist, verschiedene Namen zu verwenden, wenn Sie die gleichen Namen haben nicht wollen. Einige Ungarisch-Notation Variation in den Sinn kommt (ich könnte einige Hass dafür bekommen):

//data members 
int x_; 
int y_; 
int width_; 
int height_; 
//constructor 
A::A(int x, int y, int width, int height) : 
    x_(x), 
    y_(y), 
    width_(width), 
    height_(height) 
{ 
} 

Aber es ist nichts falsch mit dem ersten Vorschlag.

+0

17.4.3.1.2/1: Jeder Name, der mit einem Unterstrich beginnt, ist für die Implementierung reserviert, um als Name im globalen Namespace verwendet zu werden. –

+0

@JohnDibling Warum habe ich gedacht, dass das nur für Makros gilt? Naja ... ich denke, es gibt noch eine Sache, die ich hasse, wenn ich auf alten Code zurückschaue, den ich geschrieben habe ...: D –

+0

Was ist falsch an der ungarischen Schreibweise? ;) Obwohl dies eigentlich nur ein vorangestellter Name ist, nicht wirklich eine Variante der ungarischen Notation. –

2

Obwohl Sie das Problem vermeiden können, indem Sie die Initialisierungsliste des Konstruktors verwenden, schlage ich vor, eine Konvention für die Benennung von Datenelementen zu befolgen, zum Beispiel eine nachlaufende _ oder eine führende m_. Sonst sind Namenskonflikte sehr wahrscheinlich, besonders wenn Sie Mitglieder mit Namen wie x und y haben.

class A 
{ 
    public: 

    A(int x, int y, int width, int height) : x_(x), y_(y), with_(width), height_(height) {} 

    int x_; 
    int y_; 
    int width_; 
    int height_; 
}; 
+0

Ich sah oft diese (Unterstrich) Konvention - kennen Sie ihren Ursprung? Danke für jeden Hinweis. – Wolf

+0

this-> ist auch eine gute Möglichkeit, aus dem lokalen Bereich zu disambiguieren. – partyd

5

Wenn müssen Sie Zuweisungen im Konstruktor verwenden (wie auf die Verwendung einer Liste von Initialisierungen gegenüber, die bevorzugt wird) das spezifische Muster dieses Problem zu beheben ist this Zeiger zu verwenden, wie folgt:

this->a = a; 
0

Sie können nur die Namen der Konstruktorargumente ändern. Wenn Sie

A::A(int x, int y, int width, int height) 
{ 
    x = x; 
    y = y; 
    width = width; 
    height = height; 
} 

schreiben dann bist du die Argumente der Konstruktor selbst zuweisen, die tatsächlichen Instanzvariablen verlassen nicht initialisiert, das ist, warum Sie falsche Werte zu bekommen.

Die allgemeine Lösung schlage ich vor (und verwende allgemein) ist den Namen der Argumente der Konstruktor-Methode zu ändern:

A::A(int x_initial, int y_initial, int width_initial, int height_initial) 
{ 
    x = x_initial; 
    y = y_initial; 
    width = width_initial; 
    height = height_initial; 
} 
+0

Ja, das habe ich gemacht, aber anstatt "_initial" habe ich "a" angehängt. – corazza

+0

@Bane und was ist los damit? –

+0

Nun scheint es eine "hässliche" Lösung zu sein, und ich vermutete, dass es etwas mit meinem Verständnis von Konstruktoren falsch war ... – corazza

2

Wenn möglich, ist es besser, Datenelemente über die Initialisiererliste zu setzen, In diesem Fall gibt es kein Problem mit Argumenten, die die Membernamen überschatten. Eine weitere Alternative ist die Verwendung von this->foo = foo; im Body des Konstruktors. Ein ähnliches Problem besteht für Setter, aber jetzt können Sie die Initialisiererlistenlösung nicht mehr verwenden. Sie stecken fest mit this->foo = foo; - oder einfach andere Namen für Argumente und Mitglieder.

Einige Leute hassen Argumente, die Datenmitglieder schatten; Mehrfache Kodierungsstandards sagen explizit, dies nie zu tun. Andere denken, dass diese Art von Beschattung, zumindest für Konstrukteure und Setter, das Miauen der Katze ist. Ich erinnere mich an das Lesen von ein oder zwei Codierungsstandards (aber ich erinnere mich nicht daran), die diese Art von Shadowing als "sollte" (aber nicht "soll") praktizieren.

Eine letzte Option besteht darin, Shadowing in der Funktionsdeklaration zu verwenden, um Lesern einen Hinweis darauf zu geben, was die Funktion macht, aber unterschiedliche Namen in der Implementierung zu verwenden.

Update: Was ist "Shadowing"?

#include <iostream> 

void printi (int i) { std::cout << "i=" << i << "\n"; } 

int i = 21; 

int main() { 
    printi (i); 
    int i = 42; 
    printi (i); 
    for (int i = 0; i < 3; ++i) { 
     printi (i); 
     int i = 10; 
     printi (i); 
    } 
    printi (i); 
} 

Die innerste Erklärung i, int i=10, shadows die Variable i in der for Anweisung deklariert, was wiederum die Variable i bei Funktionsumfang erklärt Schatten, die wiederum i die globale Variable Schatten.

Im Problem auf der Hand, die Argumente x, y, width und height auf den Nicht-Standard-Konstruktor für die Klasse A Schatten der Mitgliedsdaten mit den gleichen Namen wie die Argumente.

Ihre width=width; hat nichts getan, weil das Argument width das Datenelement width schattiert (versteckt). Wenn Sie zwei oder mehr Variablen mit demselben Namen haben, die in verschiedenen Bereichen deklariert wurden, ist der Gewinner immer der Name mit dem innersten Gültigkeitsbereich. Im Allgemeinen gewinnt immer der Name mit dem innersten Umfang.

+0

Was genau bezeichnen Sie als "Shadowing"? – corazza

+0

@Bane - Was ist "Shadowing?" Shadowing: (1) Ein Foltergerät, mit dem geprüft wird, ob CS 101-Schüler Scoping verstehen. (2) Wenn eine Variable in einem Bereich deklariert wird, hat sie den gleichen Namen wie eine Variable, die in einem äußeren Bereich deklariert ist. (3) Was hast du mit deinem Konstruktor gemacht? (4) Ein potenzielles Problem, das durch die Zusammenstellung von "Schatten" aufgefangen wird. (5) Siehe meine aktualisierte Antwort. –

+0

Ich verstehe jetzt, danke! – corazza

Verwandte Themen