2012-10-10 31 views
5

thể trùng lặp:
Members vs method arguments access in C++Mâu thuẫn giữa tên thành viên và tên tham số constructor

Tôi có một lớp học có một số thành viên, giống như x, y, widthheight. Trong constructor của nó, tôi sẽ không làm điều này:

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

này không thực sự có ý nghĩa và khi biên soạn với g ++ x, y, widthheight trở thành giá trị kỳ lạ (ví dụ -1405737648).

Cách tối ưu để giải quyết những xung đột đặt tên này là gì?

+3

Euh, gắn một 'a' vào tên đối số? –

+0

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

+0

nếu bạn muốn thanh lịch, * trước * pend 'a', tạo thành một bài báo không xác định bằng tiếng Anh: 'anX, aY, aWidth, aHaight' vv Rõ ràng, không thể sử dụng cùng một số nhận dạng để tham chiếu đến hai biến khác nhau trong cùng một phạm vi. Xem câu trả lời của tôi. –

Trả lời

17

Bạn có thể sử dụng danh sách khởi tạo chỉ tốt với những cái tên giống nhau:

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

Một cách khác là sử dụng tên gọi khác nhau, nếu bạn không muốn có cùng tên. Một số biến thể ký hiệu Hung-ga-ri đến với tâm trí (tôi có thể bị ghét vì điều này):

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

Nhưng không có gì sai với đề xuất đầu tiên.

+0

17.4.3.1.2/1: Mỗi tên bắt đầu bằng dấu gạch dưới được dành riêng cho việc triển khai để sử dụng làm tên trong không gian tên chung. –

+0

@JohnDibling tại sao tôi nghĩ rằng chỉ áp dụng cho các macro? Oh well ... đoán có một điều nữa tôi sẽ ghét khi tôi nhìn lại mã cũ tôi đã viết ...: D –

+0

có gì sai với ký pháp Hungary? ;) Mặc dù, điều này thực sự chỉ là một tên tiền tố, không thực sự là một biến thể của ký hiệu Hungary. –

2

Mặc dù bạn có thể tránh sự cố bằng cách sử dụng danh sách khởi tạo của hàm tạo, tôi đề nghị theo quy ước đặt tên thành viên dữ liệu, ví dụ: _ hoặc m_ hàng đầu. Nếu không, bạn rất có khả năng có xung đột tên, đặc biệt nếu bạn có các thành viên có tên như xy.

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

Tôi thường thấy quy ước này (theo dấu gạch dưới) - bạn có biết nguồn gốc của nó không? Cảm ơn mọi gợi ý. – Wolf

+0

this-> cũng là một cách tuyệt vời để phân biệt từ phạm vi địa phương. – partyd

5

Nếu bạn phải sử dụng bài tập trong các nhà xây dựng (như trái ngược với cách sử dụng một danh sách các initializers, được ưa thích) mô hình cụ thể để giải quyết vấn đề này là sử dụng this con trỏ, như sau:

this->a = a; 
0

Bạn chỉ có thể thay đổi tên của các đối số hàm tạo. Khi bạn viết

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

sau đó bạn gán lập luận của các nhà xây dựng cho riêng mình, rời khỏi biến ví dụ thực tế uninitialized, đó là lý do tại sao bạn đang nhận được giá trị không có thật.

Các giải pháp chung tôi đề nghị (và rộng rãi sử dụng) là thay đổi tên của các đối số của phương thức khởi tạo:

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

Vâng, đó là những gì tôi đã làm, nhưng thay vì "_initial" tôi nối thêm "a". – corazza

+0

@Bane và có vấn đề gì với điều đó? –

+0

Vâng nó có vẻ là một "xấu xí" giải pháp, và tôi cho rằng nó đã gợi ý rằng có một cái gì đó sai với sự hiểu biết của tôi về các nhà thầu ... – corazza

2

Nếu có thể, nó tốt hơn để thiết lập dữ liệu các thành viên thông qua danh sách initializer, trong trường hợp đó không có vấn đề với các đối số có tên thành viên bóng tối. Một cách khác là sử dụng this->foo = foo; trong phần thân của hàm tạo. Một vấn đề tương tự tồn tại đối với người định cư, nhưng bây giờ bạn không thể sử dụng giải pháp danh sách khởi tạo. Bạn đang mắc kẹt với this->foo = foo; - hoặc chỉ sử dụng các tên khác nhau cho các đối số và thành viên.

Một số người thực sự ghét các đối số làm bóng các thành viên dữ liệu; nhiều tiêu chuẩn mã hóa một cách rõ ràng nói không bao giờ làm điều này. Những người khác nghĩ rằng loại bóng tối này, ít nhất là cho các nhà xây dựng và người định cư, là meow của mèo. Tôi nhớ lại việc đọc một hoặc hai tiêu chuẩn mã hóa (nhưng tôi không nhớ cái nào) đã chỉ định loại bóng tối này là một thực hành "nên" (nhưng không phải "phải").

Một tùy chọn cuối cùng là sử dụng tính năng đánh bóng trong khai báo hàm để cung cấp cho người đọc một gợi ý về chức năng, nhưng sử dụng các tên riêng biệt trong quá trình triển khai.

Cập nhật: "shadowing" là gì?

#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); 
} 

Việc kê khai trong cùng của i, int i=10, bóng tối biến i tuyên bố trong báo cáo for, do đó bóng tối biến i tuyên bố tại phạm vi chức năng, do đó bóng tối biến toàn cầu i.

Trong vấn đề ở bàn tay, các đối số x, y, widthheight để các nhà xây dựng không mặc định cho lớp A bóng các dữ liệu thành viên có tên giống như những đối số.

width=width; của bạn không làm gì vì đối số width bóng (ẩn) thành viên dữ liệu width. Khi bạn có hai hoặc nhiều biến có cùng tên được khai báo ở các phạm vi khác nhau, người chiến thắng luôn là tên có phạm vi trong cùng. Nói chung, nó luôn là tên có phạm vi trong cùng nhất thắng.

+0

Chính xác thì bạn gọi là "bóng tối" là gì? – corazza

+0

@Bane - "Bóng tối" là gì? Bóng tối: (1) Một thiết bị tra tấn được sử dụng để kiểm tra xem các học sinh CS 101 có hiểu được phạm vi hay không. (2) Khi một biến được khai báo ở một phạm vi nào đó có cùng tên với một biến được khai báo ở một số phạm vi bên ngoài. (3) Những gì bạn đã làm với nhà xây dựng của bạn. (4) Một vấn đề tiềm năng bị bắt khi biên dịch bằng '-Wshadow'. (5) Xem câu trả lời cập nhật của tôi. –

+0

Tôi hiểu ngay bây giờ, cảm ơn bạn! – corazza

Các vấn đề liên quan