Hàm tạo rõ ràng lấy nhiều đối số


88

Việc tạo một hàm tạo có nhiều đối số explicitcó tác dụng (hữu ích) nào không?

Thí dụ:

class A {
    public:
        explicit A( int b, int c ); // does explicit have any (useful) effect?
};

Câu trả lời:


120

Cho đến C ++ 11, vâng, không có lý do gì để sử dụng explicittrên một hàm tạo nhiều đối số.

Điều đó thay đổi trong C ++ 11, do danh sách trình khởi tạo. Về cơ bản, quá trình sao chép-khởi tạo (nhưng không phải khởi tạo trực tiếp) với danh sách bộ khởi tạo yêu cầu rằng hàm tạo không được đánh dấu explicit.

Thí dụ:

struct Foo { Foo(int, int); };
struct Bar { explicit Bar(int, int); };

Foo f1(1, 1); // ok
Foo f2 {1, 1}; // ok
Foo f3 = {1, 1}; // ok

Bar b1(1, 1); // ok
Bar b2 {1, 1}; // ok
Bar b3 = {1, 1}; // NOT OKAY

5
Tôi nghĩ câu trả lời này sẽ tốt hơn với lời giải thích "Tại sao tôi muốn điều đó" hoặc "Khi nào thì điều này hữu ích".
MateuszL

@MateuszL Câu trả lời của Edgar có lẽ đưa ra lập luận tốt nhất cho việc tại sao nó có thể hữu ích (và được cho là xứng đáng được đánh dấu). Tuy nhiên, lý do nó ở đó đơn giản là vì nó là phần mở rộng hợp lý của ngữ nghĩa hiện có explicit. Cá nhân tôi sẽ không bận tâm đến việc tạo các hàm tạo đa đối số explicit.
Sneftel

31

Bạn sẽ tình cờ gặp nó để khởi tạo dấu ngoặc nhọn (ví dụ: trong mảng)

struct A {
        explicit A( int b, int c ) {}
};

struct B {
         B( int b, int c ) {}
};

int main() {
    B b[] = {{1,2}, {3,5}}; // OK

    A a1[] = {A{1,2}, A{3,4}}; // OK

    A a2[] = {{1,2}, {3,4}}; // Error

    return 0;
}

24

Những câu trả lời xuất sắc của @StoryTeller và @Sneftel là lý do chính. Tuy nhiên, IMHO, điều này có ý nghĩa (ít nhất là tôi làm điều đó), như một phần của việc kiểm chứng trong tương lai những thay đổi sau này đối với mã. Hãy xem xét ví dụ của bạn:

class A {
    public:
        explicit A( int b, int c ); 
};

Mã này không trực tiếp hưởng lợi từ explicit.

Một thời gian sau, bạn quyết định thêm giá trị mặc định cho c, vì vậy giá trị này trở thành:

class A {
    public:
        A( int b, int c=0 ); 
};

Khi làm điều này, bạn đang tập trung vào ctham số - khi nhìn lại, nó phải có giá trị mặc định. Bạn không nhất thiết phải tập trung vào việc liệu Abản thân nó có nên được xây dựng ngầm hay không. Thật không may, thay đổi này explicitcó liên quan trở lại.

Vì vậy, để truyền đạt rằng một ctor là explicit, nó có thể phải trả tiền để làm như vậy khi lần đầu tiên viết phương thức.


Nhưng còn trường hợp khi người bảo trì thêm mặc định đó và kết luận rằng kết quả sẽ có sẵn dưới dạng một hàm tạo chuyển đổi? Bây giờ họ phải loại bỏ những explicitthứ đã tồn tại mãi mãi và bộ phận hỗ trợ công nghệ sẽ tràn ngập các cuộc gọi về sự thay đổi đó và dành hàng giờ để giải thích rằng đó explicitchỉ là tiếng ồn và việc loại bỏ nó là vô hại. Cá nhân tôi không giỏi dự đoán tương lai cho lắm; thật khó để quyết định giao diện sẽ trông như thế nào bây giờ .
Pete Becker

@PeteBecker Đó là một điểm tốt. Cá nhân tôi nghĩ rằng hai trường hợp là không đối xứng và nó phổ biến hơn nhiều khi đặt các tham số mặc định (hoặc xóa chúng) để vô tình làm cho lớp có thể xây dựng một cách ngầm định, sau đó thực sự nhận ra rằng khi nhìn lại thì nó phải như vậy. Nói như vậy, đây là những cân nhắc "nhẹ nhàng", và có thể khác nhau giữa mọi người / dự án / v.v., hoặc thậm chí chỉ là vấn đề sở thích.
Ami Tavory

8

Đây là năm xu của tôi cho cuộc thảo luận này:

struct Foo {
    Foo(int, double) {}
};

struct Bar {
    explicit Bar(int, double) {}
};

void foo(const Foo&) {}
void bar(const Bar&) {}

int main(int argc, char * argv[]) {
    foo({ 42, 42.42 }); // valid
    bar({ 42, 42.42 }); // invalid
    return 0;
}

Như bạn có thể dễ dàng thấy, explicitngăn không cho sử dụng danh sách bộ khởi tạo cùng với barhàm phụ trợ vì hàm tạo của struct Barđược khai báo là explicit.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.