2012-10-10 11 views
5

Powiel możliwe:
Members vs method arguments access in C++Konflikty między nazwami członkowskich i nazwy argument konstruktora

Mam klasa, która ma kilka elementów, takich jak x, y, width i height. W jej konstruktora, nie byłoby to zrobić:

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

To naprawdę nie ma sensu i kiedy skompilowane z g ++ x, y, width, a height się wartościami dziwne (np -1405737648).

Jaki jest optymalny sposób rozwiązania tych konfliktów nazw?

+3

Euh, dołączając 'a' do nazw argumentów? –

+0

'A :: A (int xa, int ya, int widtha, int heighta)' – corazza

+0

jeśli chcesz być elegancki, * pre * pend "a", tworząc angielski nieokreślony artykuł: 'anX, aY, aWidth, aHaight' itp. Oczywiście ten sam identyfikator nie może być użyty w odniesieniu do dwóch różnych zmiennych w tym samym zakresie. Zobacz moją odpowiedź. –

Odpowiedz

17

Można używać list inicjujących dobrze z tymi samymi nazwami:

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

Alternatywą jest stosowanie różnych nazw, jeśli nie chcą mieć te same nazwy. Pewne różnice węgiersko-notacja przychodzi do głowy (mógłbym dostać jakąś nienawiść do tego):

//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) 
{ 
} 

Ale nie ma nic złego w pierwszej sugestii.

+0

17.4.3.1.2/1: Każda nazwa zaczynająca się od podkreślenia jest zarezerwowana dla implementacji do użycia jako nazwa w globalnej przestrzeni nazw. –

+0

@JohnDibling Dlaczego myślę, że dotyczy tylko makr? No cóż ... myślę, że jest jeszcze jedna rzecz, której nie zniosę, gdy spojrzę wstecz na stary kod, który napisałem ...: D –

+0

co jest nie tak z notacją węgierską? ;) Chociaż jest to właściwie tylko prefiksowana nazwa, a nie wariant odmiany węgierskiej. –

2

Mimo że można uniknąć problemu za pomocą listy inicjalizacyjnej konstruktora, sugeruję zastosowanie konwencji nazywania elementów danych, na przykład końcowej _ lub wiodącej m_. W przeciwnym razie bardzo prawdopodobne jest wystąpienie konfliktów nazw, szczególnie jeśli masz członków o nazwach takich jak x i y.

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

Często widziałem tę konwencję (trailing underscore) - czy znasz jej pochodzenie? Dzięki za podpowiedź. – Wolf

+0

this-> to także świetny sposób na ujednoznacznienie z lokalnego zakresu. – partyd

5

Jeśli trzeba użyć zadania w konstruktorze (w przeciwieństwie do korzystania z listy inicjalizatorów, który jest korzystny) specyficzny wzór, aby rozwiązać ten problem jest użycie this wskaźnik, co następuje:

this->a = a; 
0

Możesz po prostu zmienić nazwy argumentów konstruktora. Kiedy piszesz

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

to jesteś przypisanie argumenty konstruktora do siebie, pozostawiając rzeczywiste instancji zmiennych niezainicjowanymi, dlatego dostajesz fałszywe wartości.

Ogólne rozwiązanie sugeruję (i powszechnie używać) jest zmiana nazwy argumentów metody konstruktora:

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

Tak, właśnie to zrobiłem, ale zamiast "_initial" dodałem "a". – corazza

+0

@Bane i co w tym złego? –

+0

Cóż, wydaje się to być "brzydkie" rozwiązanie i przypuszczam, że sugerowało, że było coś nie tak z moim rozumieniem konstruktorów ... – corazza

2

Jeśli to możliwe, to lepiej ustawić członków danych poprzez listę inicjatora, w takim przypadku nie ma problemu z argumentami, że nazwy członków shadow. Inną alternatywą jest użycie this->foo = foo; w ciele konstruktora. Podobny problem występuje w ustawiaczach, ale teraz nie można użyć rozwiązania listy inicjalizacyjnej. Utknąłeś z this->foo = foo; - lub po prostu używaj różnych nazw dla argumentów i członków.

Niektórzy ludzie naprawdę nienawidzą argumentów, które śledzą członków danych; wiele standardów kodowania wyraźnie mówi, że nigdy tego nie robi. Inni uważają, że ten rodzaj cieniowania, przynajmniej dla konstruktorów i seterów, jest miauczeniem kota. Przypominam sobie przeczytanie jednego lub dwóch standardów kodowania (ale nie pamiętam, który), który wyznaczył ten rodzaj cieniowania jako "powinien" (ale nie "powinien") praktykę.

Ostatnią opcją jest użycie cieniowania w deklaracji funkcji, aby dać czytelnikom wskazówkę co do funkcji, ale użyć różnych nazw w implementacji.

Aktualizacja: Co to jest "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); 
} 

Głębsza deklaracja i, int i=10, cienie zmienną i zadeklarowaną w oświadczeniu for, co z kolei cienie zmienną i zadeklarowana w zakresie funkcji, które z kolei cienie zmienną globalną i.

W problemu pod ręką, argumenty x, y, width, a height do non-domyślnego konstruktora dla klasy A cienia dane członkowskie o tych samych nazwach jak te argumenty.

Twoja width=width; nic nie zrobiła, ponieważ argument width cienie (ukrywa) element danych width. Jeśli masz dwie lub więcej zmiennych o tej samej nazwie, które zostały zadeklarowane w różnych zakresach, zwycięzcą jest zawsze nazwa z najgłębszym zakresem. Ogólnie rzecz biorąc, zawsze wygrywa nazwa o najgłębszym zasięgu.

+0

Co dokładnie określasz jako "shadowing"? – corazza

+0

@Bane - Co to jest "shadowing?" Shadowing: (1) Urządzenie do tortur używane do testowania, czy uczniowie CS 101 rozumieją scoping. (2) Gdy zmienna zadeklarowana w pewnym zakresie ma taką samą nazwę jak zmienna zadeklarowana w jakimś zewnętrznym zakresie. (3) Co zrobiłeś ze swoim konstruktorem. (4) Potencjalny problem, który został przechwycony przez kompilację przy pomocy '-Wshadow'. (5) Zobacz moją zaktualizowaną odpowiedź. –

+0

Teraz rozumiem, dziękuję! – corazza

Powiązane problemy