2012-06-20 21 views
13

Theo Scott Meyers, để ngăn chặn sự lặp lại mã trong phiên bản const của getter và phiên bản không const của getter, hãy gọi phiên bản const của phương thức từ phiên bản không const: static_cast<const A&>(*this).Methodology();tuy nhiên, trong tình cờ sử dụng do một Visual Assist X Intellisense overzealous tôi gõ: const_cast<const A&>(*this).Methodology(); và nó đã làm việc tốt.C++ sự khác biệt giữa việc thêm const-ness với static_cast và const_cast của đối tượng "this"?

Có bất kỳ sự khác biệt nào trong trường hợp này khi sử dụng một dàn diễn viên cụ thể?

IDE sử dụng: Visual Studio 2010.

+1

Tôi tự hỏi tại sao Scott khuyến khích sử dụng static_cast trong khi const_cast có vẻ như là lựa chọn phù hợp hơn ở đây, cũng thể hiện rõ hơn ý định? Hay bạn không sử dụng chính xác theo cách anh ấy nói? – stijn

+0

@stijn: Tôi cũng đã tự hỏi điều tương tự. 'const_cast' cảm thấy hơi tự nhiên hơn với tôi ngay cả đối với hướng an toàn hơn là thêm' const'. –

+0

@CharlesBailey: xem câu trả lời của tôi để có khả năng thấy lý do tại sao anh ấy không quảng cáo cái này với người khác. – Casey

Trả lời

5

Giả sử rằng các loại thisA*, không có sự khác biệt.

Nói chung const_cast thể cast aways các const specifier (từ bất kỳ mức độ gián tiếp hoặc mẫu tham số)

static_cast<> thể đúc một loại khác nếu loại mục tiêu là trong phân cấp kiểu của nguồn.

Họ không thể thực hiện công việc của nhau.

Lý do cả hai đều làm việc trong trường hợp của bạn là bởi vì bạn có giới thiệu const-Ness, như trái ngược với khi đưa nó đi (gọi từ phiên bản không const của hàm loại thisA*, không const). Bạn cũng có thể viết

const A& tmp = *this; 
tmp.Methodology(); 

và nó có thể đã hoạt động mà không cần phải đúc. Việc đúc được sử dụng cho sự tiện lợi và terseness để không phải giới thiệu một biến mới.

Note: bạn có thể sử dụng static_cast<> đây như bạn biết mà bạn đang casting cho đúng loại. Trong trường hợp khác (khi bạn không thể chắc chắn), bạn cần phải sử dụng dynamic_cast<> mà không kiểm tra kiểu thời gian chạy để đảm bảo việc chuyển đổi có giá trị

+0

'A' là một loại lớp,' this' mặc định là 'const * A'. – Casey

+0

@Casey - Tôi đã tìm ra điều đó; vấn đề là nó là lớp mà bạn đang làm điều này, không phải là một lớp con (trong trường hợp đó 'const_cast <>' sẽ thất bại) – Attila

+1

@Casey - kiểu 'this' là' const A * '(chính xác hơn 'const A * const') nếu bạn đang ở trong một hàm' const' member, nếu không nó là 'A *' (chính xác hơn 'A * const') – Attila

3

Sau khi đọc lại khoản 3 từ Effective C++ 3rd Ed. Tôi nhận ra rằng mình đã thực sự ủng hộ sử dụng cả . Thêm const để gọi phiên bản const, sau đó bỏ đi giá trị trả về (nếu có). Trong trường hợp đặc biệt của tôi, không có giá trị trả về const, chỉ cần một const chức năng nên quấn-by-const_cast <> phiên bản là không cần thiết và có hiệu lực khiến có có sự khác biệt giữa hai cuộc gọi trong câu hỏi

(. p 13) khoản 3: Sử dụngconstbất cứ khi nào có thể

...

(p.23) Tránh sao chép trongconstphi constthành viên Chức năng

... Những gì bạn thực sự muốn làm là thực hiện operator [] chức năng một lần và sử dụng nó hai lần. Tức là, bạn muốn có một phiên bản của nhà cung cấp [] gọi cho người khác. Và điều đó khiến chúng ta phải bỏ đi chòm sao.

... Đúc đi những const trên giá trị trả về là an toàn, trong trường hợp này, vì bất cứ ai gọi là các nhà điều hành phi const [] phải có một phi const đối tượng trong nơi đầu tiên .... Vì vậy, có không const operator [] gọi const phiên bản là một cách an toàn để tránh mã trùng lặp, mặc dù nó đòi hỏi một dàn diễn viên ...

class TextBlock { 
public: 

... 

    const char& operator[](std::size_t position) const  //same as before 
    { 
     ... 
     ... 
     ... 
     return text[position]; 
    } 

    char& operator[](std::size_t position)  //now just calls const op[] 
    { 
     //cast away const on op[]'s return type; 
     //add const to *this's type; 
     //call const version of op[]. 
     return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]); 
    } 
... 
}; 

Như bạn có thể thấy, mã có hai phôi, không phải một. Chúng tôi muốn các nhà điều hành không const [] ... Để tránh đệ quy vô hạn, chúng tôi phải xác định rằng chúng tôi muốn gọi nhà điều hành const [], nhưng không có cách nào trực tiếp để thực hiện điều đó. Thay vào đó, chúng tôi đúc * này từ loại có nguồn gốc của nó của TextBlock &-const TextBlock &. Có, chúng tôi sử dụng tính năng truyền tới thêm const! Vì vậy, chúng ta có hai phôi: một để thêm const để * này (vì vậy mà gọi chúng tôi để operator [] sẽ gọi const version), thứ hai để tháo const từ * const giá trị trả về của toán tử [].