2008-10-06 15 views
41

Tôi biết bạn có thể sử dụng từ khóa C++ 'rõ ràng' cho các nhà xây dựng của các lớp học để ngăn chặn việc chuyển đổi kiểu tự động. Bạn có thể sử dụng lệnh này để ngăn việc chuyển đổi các tham số cho một phương thức lớp không?Bạn có thể sử dụng từ khóa rõ ràng để ngăn việc tự động chuyển đổi các tham số phương thức không?

Tôi có hai thành viên lớp học, một thành viên tham gia bool dưới dạng tham số, một hàm khác là int không dấu. Khi tôi gọi hàm với một int, trình biên dịch chuyển đổi param thành một bool và được gọi là phương thức sai. Tôi biết cuối cùng tôi sẽ thay thế bool, nhưng bây giờ không muốn phá vỡ các thói quen khác như thói quen mới này được phát triển.

+0

Tự hỏi điều tương tự này và nghĩ rằng đây sẽ là cú pháp hữu ích cho một số chức năng miễn phí nhất định. Thông thường tôi muốn tham chiếu đến một lớp dẫn xuất để ngầm tạo ra lớp cơ sở, ngoại trừ trong trường hợp việc cắt không mong muốn có thể xảy ra, chẳng hạn như với hàm swap(). Có trao đổi (rõ ràng Foo & lhs, rõ ràng Foo & rhs) sẽ được an ủi. –

Trả lời

51

Không, bạn không thể sử dụng rõ ràng, nhưng bạn có thể làm điều này thay vì:

class ClassThatOnlyTakesBoolsAndUIntsAsArguments 
{ 
public: 
    void Method(bool arg1); 
    void Method(unsigned int arg1); 

    // Below just an example showing how to do the same thing with more arguments 
    void MethodWithMoreParms(bool arg1, SomeType& arg2); 
    void MethodWithMoreParms(unsigned int arg1, SomeType& arg2); 

private: 
    template<typename T> 
    void Method(T arg1); 

    // Below just an example showing how to do the same thing with more arguments 
    template<typename T> 
    void MethodWithMoreParms(T arg1, SomeType& arg2); 
}; 

Lặp lại mô hình này cho mọi phương pháp mà mất bool hoặc unsigned int. Không cung cấp triển khai cho phiên bản templatized của phương thức.

Điều này sẽ buộc người dùng luôn gọi một cách rõ ràng phiên bản bool hoặc unsigned int.

Bất kỳ nỗ lực nào để gọi Method với loại khác ngoài bool hoặc unsigned int sẽ không biên dịch được vì thành viên là riêng tư, ngoại trừ tiêu chuẩn cho quy tắc hiển thị, tất nhiên (bạn bè, cuộc gọi nội bộ, v.v.). Nếu một cái gì đó mà có quyền truy cập gọi các phương pháp riêng, bạn sẽ nhận được một lỗi linker.

+0

Nhưng điều này sẽ vô hiệu hóa TẤT CẢ các chuyển đổi tự động. – Lev

+0

Có, nó sẽ vô hiệu hóa TẤT CẢ các chuyển đổi tự động. Dan muốn "ngăn chặn việc chuyển đổi các tham số cho một phương thức lớp", cho mỗi văn bản câu hỏi và phương thức này thỏa mãn điều đó. Có nhiều cách sử dụng chuyên môn mẫu mà chúng tôi có thể 'ánh xạ' các loại cơ bản cho các phương pháp cụ thể nếu muốn. –

0

Trình biên dịch đã cảnh báo "gọi không rõ ràng", điều này sẽ là đủ.

Tôi đã thực hiện phát triển TDD và không nhận ra rằng tôi đã quên triển khai cuộc gọi tương ứng trong đối tượng giả.

+0

Bạn có thể muốn xem xét cập nhật câu hỏi để phản ánh rằng những gì bạn đã chỉ ra là vấn đề (phương pháp sai được chọn) không thực sự là vấn đề. Tôi đã xem xét lại điều này cho các mục đích của riêng tôi và nhận ra rằng ngay cả giải pháp của tôi không nhất thiết phải giải quyết điều đó, tùy thuộc vào các đối số. –

-1

Bạn cũng có thể viết phiên bản int gọi lệnh bool.

+1

Anh ta muốn ngăn chặn hành vi như vậy. –

12

No. explicit ngăn chuyển đổi tự động giữa các lớp cụ thể, bất kể ngữ cảnh. Và tất nhiên bạn không thể làm điều đó cho các lớp học tích hợp.

+0

Đã bỏ phiếu; điều này trả lời đúng câu hỏi, sau khi tất cả. –

0

bool Là một int được giới hạn ở 0 hoặc 1. Đó là toàn bộ khái niệm trả về 0 ;, nó giống hệt như trả về false (không sử dụng mã này).

+1

Tôi tin rằng bool là một loại thực tế của riêng nó, trong C++. –

+0

Vâng đó là một loại, nhưng loại có thể chỉ giữ giá trị int là 0 và 1. thực sự nếu tôi nhớ người hướng dẫn C++ của tôi từ ngày cắt dán của tôi, 0 là sai và bất cứ điều gì khác là đúng sự thật. Đây là hoạt động bên trong của bool, không phải là nó nên được áp dụng như thế nào. – WolfmanDragon

+0

Không phải là một jerk, nhưng "ngày cắt dán"? Hehehe ... làm tôi cười khúc khích. –

2

Điều gì đó có thể phù hợp với bạn là sử dụng mẫu. Phần sau hiển thị chức năng mẫu foo<>() đang được chuyên biệt cho bool, unsigned intint. Hàm main() cho biết cách các cuộc gọi được giải quyết. Lưu ý rằng các cuộc gọi sử dụng hằng số int không chỉ định hậu tố loại sẽ giải quyết thành foo<int>(), do đó bạn sẽ gặp lỗi khi gọi foo(1) nếu bạn không chuyên về int. Nếu trường hợp này xảy ra, người gọi sử dụng hằng số nguyên nguyên sẽ phải sử dụng hậu tố "U" để nhận cuộc gọi để giải quyết (đây có thể là hành vi bạn muốn).

Nếu không, bạn sẽ phải chuyên về int và sử dụng "U" hậu tố hoặc đúc nó vào một unsigned int trước khi chuyển lên phiên bản unsigned int (hoặc có thể làm một khẳng định rằng giá trị không phải là tiêu cực, nếu đó là những gì bạn muốn).

#include <stdio.h> 

template <typename T> 
void foo(T); 

template <> 
void foo<bool>(bool x) 
{ 
    printf("foo(bool)\n"); 
} 


template <> 
void foo<unsigned int>(unsigned int x) 
{ 
    printf("foo(unsigned int)\n"); 
} 


template <> 
void foo<int>(int x) 
{ 
    printf("foo(int)\n"); 
} 



int main() 
{ 
    foo(true); 
    foo(false); 
    foo(static_cast<unsigned int>(0)); 
    foo(0U); 
    foo(1U); 
    foo(2U); 
    foo(0); 
    foo(1); 
    foo(2); 
} 
+0

Tôi cũng nghĩ về cách làm theo cách này; có foo gọi foo để ánh xạ rõ ràng. Đây là cách tốt hơn nếu anh ấy muốn cho phép một số chuyển đổi nhưng không phải tất cả. –

+0

Thực ra, đây thực sự là phương pháp giống như của bạn. Khi tôi nhanh chóng quét máy của bạn ngay trước khi đăng bài, tôi đã bị loại bỏ bởi các nguyên mẫu đa tham số và nghĩ rằng kỹ thuật của bạn đã làm điều gì đó khác biệt mà tôi không hoàn toàn hiểu. Tôi nên đọc kỹ hơn. –

+0

Ah - các phiên bản đa tham số được cho là phải làm rõ rằng nó không chỉ áp dụng cho các phương pháp parm duy nhất, và chỉ có các đối số trong câu hỏi đã được templatized. Có lẽ họ khó hiểu hơn là có lợi? Tôi sẽ thêm một bình luận để xóa nó. –

6

Sau đây là một wrapper rất cơ bản mà có thể được sử dụng để tạo ra một typedef mạnh:

template <typename V, class D> 
class StrongType 
{ 
public: 
    inline explicit StrongType(V const &v) 
    : m_v(v) 
    {} 

    inline operator V() const 
    { 
    return m_v; 
    } 

private: 
    V m_v; // use V as "inner" type 
}; 

class Tag1; 
typedef StrongType<int, Tag1> Tag1Type; 


void b1 (Tag1Type); 

void b2 (int i) 
{ 
    b1 (Tag1Type (i)); 
    b1 (i);    // Error 
} 

Một tính năng tuyệt vời của phương pháp này, là bạn cũng có thể phân biệt giữa các thông số khác nhau với cùng kiểu. Ví dụ: bạn có thể có các thông tin sau:

class WidthTag; 
typedef StrongType<int, WidthTag> Width; 
class HeightTag; 
typedef StrongType<int, HeightTag> Height; 

void foo (Width width, Height height); 

Sẽ rõ ràng đối với khách hàng của 'foo' đối số nào.

+0

Mặc dù câu hỏi khá cũ (9 năm suy nghĩ): Mỗi lần tôi muốn gọi 'foo' với hai tham số Integer, tôi phải viết' foo (Height (int_1), Width (int_2)) 'sẽ tìm thấy chuyển đổi rõ ràng toán tử thông qua Tra cứu phụ thuộc đối số/Tìm kiếm của Koenig? – SebNag

+0

@SebTu: Không. 'Chiều cao' và' Chiều rộng' phải được tìm thấy bằng tra cứu không phải ADL. Biểu thức 'Chiều cao (int_1)' là một kiểu diễn xuất rõ ràng dẫn đến hàm tạo 'Chiều cao' được gọi. ADL không áp dụng ở đây. Vì vậy, để tham khảo 'NS :: Height' hoặc' NS :: Width' thì chúng ta phải sử dụng một chỉ thị bằng cách sử dụng/khai báo hoặc xác định rõ ràng tên. –