2011-01-16 32 views
22

Tôi đang đọc một cuốn sách về C++ và chính xác hơn về quá tải toán tử.C++ tại sao toán tử gán phải trả về một tham số const để tránh (a = b) = c

Ví dụ như sau:

const Array &Array::operator=(const Array &right) 
{ 
// check self-assignment 
// if not self- assignment do the copying 
return *this; //enables x=y=z 
} 

Lời giải thích được cung cấp bởi các cuốn sách về trở về ref const thay vì ref là để tránh tập như (x = y) = z. Tôi không hiểu tại sao chúng ta nên tránh điều này. Tôi hiểu rằng x = y được đánh giá đầu tiên trong ví dụ này và vì nó trả về tham chiếu const, phần = z không thể được thực thi. Nhưng tại sao?

+3

Sách nào? Điều đó có vẻ như một sự đề phòng không cần thiết đối với tôi. Tôi không thể tưởng tượng ai đó đang viết '(x = y) = z' - tại sao họ lại? Và không có parens, 'x = y = z' được phân tách thành' x = (y = z) ', điều này có ý nghĩa hoàn hảo, vì vậy không có rủi ro ở đó. –

+1

Nhưng tại sao phải làm gì? Tại sao nó là một ref const? Tại sao nó được thực hiện theo thứ tự này? Tại sao không thể gán 'z' cho (x = y)? – Lazarus

+16

@antronis: nhận được một cuốn sách C++ tốt hơn. – ybungalobill

Trả lời

24

(x=y) có nghĩa là x.operator=(y), trả về đối tượng x. Do đó, (x=y)=z có nghĩa là (x.operator=(y)).operator=(z). Biểu thức trong các bộ ký tự đặt x thành y và trả về x và sau đó bit ngoài đặt x thành z. Nó không đặt y thành z như bạn mong đợi, và như biểu thức x = y = z.

Hành vi này phản trực giác (tất cả chúng phải bằng nhau sau khi chuyển nhượng, đúng không?); trả về một tham chiếu const làm cho nó không thể và tránh được vấn đề.

+2

Trong khi hành vi nghe có vẻ phản trực giác, nó không phải là "vấn đề" vì nó là cái gì đó mà lập trình viên đã cố ý thực hiện (Đó là lý do tại sao họ dùng dấu ngoặc đơn) – James

+18

Ai sẽ mong đợi '(x = y) = z' 'y' đến' z'? Đây là vấn đề "rất khó" và một cuốn sách C++ không nên dành thời gian giải thích các biện pháp phòng ngừa chống lại nó. '(x = 5) = z' không đặt' 5' thành 'z'. –

+0

Nếu bạn mong đợi nhiệm vụ được kết hợp (giống như so sánh), bạn sẽ mong đợi cả ba được bằng nhau ở cuối. Naive, nhưng một giải thích hợp lý thoáng qua. Tôi đồng ý rằng hình thức này thường không nên được sử dụng và không nên được nhấn mạnh trong cuốn sách, nhưng nó là tốt để giúp trình biên dịch giúp bạn * không * bắn mình trong chân bất cứ khi nào có thể =) –

18

Không cần phải tránh điều này, trừ khi sách hướng đến các lập trình viên thường viết (x=y)=z khi chúng có nghĩa là x=y=z. Trong thực tế, không ai trong tâm trí của họ viết rằng, vì vậy việc phòng ngừa là hoàn toàn không cần thiết. Nó cũng cấm một số cấu trúc terse khác, chẳng hạn như (x=y).nonConstMember(), mà hầu như không ai viết nhưng điều đó có thể hữu ích trong một số ngữ cảnh (mặc dù chúng không được sử dụng quá mức).

@ybungalobill đúng, có sách tốt hơn.

+9

+1. Một lập trình viên "vô tình" viết '(x = y) = z' dường như về khả năng (và khi cần thiết để bảo vệ chống lại) như một lập trình viên vô tình viết' x = y + system ("rm -rf /") 'khi chúng có nghĩa là 'x = y'. –

+0

@j_random_hacker có thể xuất hiện trong "Rất tiếc, cửa sổ sai!" kịch bản ... – Calimo

+1

Nhưng tôi đã thấy 'if ((x = y) = z) ...' khi tác giả có nghĩa là 'if ((x = y) == z) ...'. –

10

Theo như tôi biết, toán tử gán không trả về tham chiếu const trong thành ngữ C++. Các kiểu tiêu chuẩn không trả về tham chiếu const.

std::string a, b, c; 
(a = b).clear(); // no objection from compiler 

Tất cả toán tử gán tùy chỉnh của tôi đã trả về tham chiếu không phải const.

Khi nghi ngờ, hãy kiểm tra Thư viện chuẩn. Nó không hoàn hảo, nhưng nó chắc chắn nhận được những thứ cơ bản như thế này đúng.

+0

Nhân vật Boost thường trả về các quảng cáo có thể thay đổi được. –

3

Tôi sẽ xem xét hành vi của các loại được cài sẵn.

Khi xác định loại của riêng bạn, tốt hơn là các toán tử hoạt động giống như kiểu tích hợp sẵn. Điều này cho phép dễ dàng áp dụng các lớp học của bạn mà không phải đào sâu vào mã của bạn để xem tại sao chúng hoạt động khác với mong đợi.

Vì vậy, nếu chúng ta nhìn vào các số nguyên:

int main() 
{ 
    int x = 5; 
    int y = 6; 
    int z = 7; 

    (x = y) = z; 
    std::cout << x << " " << y << " " << z << "\n"; 
} 

này làm việc với y không thay đổi và x được gán 7. Trong mã của bạn tôi mong chờ điều hành nhiệm vụ của mình để làm việc cùng một cách. Định nghĩa toán tử gán tiêu chuẩn:

Array& Array::operator=(Array const& rhs) 
{ 
    /* STUFF */ 
    return *this; 
} 

Nên làm điều đó tốt (giả sử/* STUFF */là chính xác).

1

Lý do duy nhất tôi có thể thấy là cuốn sách này được viết để giải thích C++ cho lập trình viên C (hoặc bởi tác giả có hiểu biết C tốt hơn so với hiểu biết C++). Bởi vì đối với một lập trình viên C, biểu thức (x = y) = z không hợp lệ đối với các kiểu dựng sẵn và có thể anh ta sẽ cố gắng thực hiện hành vi tương tự với các kiểu do người dùng xác định.

Tuy nhiên, C và C++ là các ngôn ngữ khác nhau và trong C++ biểu thức (x = y) = z hợp lệ ngay cả đối với các loại được cài sẵn. Vì vậy, nếu bạn muốn có hành vi tương tự cho các loại do người dùng xác định, bạn nên trả lại tham chiếu không phải const trong operator =.

Tôi khuyên bạn nên có một cuốn sách tốt hơn, cuốn sách không gây nhầm lẫn giữa C và C++. Họ không phải là cùng một langages, ngay cả khi họ xuất phát từ một cơ sở chung.

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