2012-02-16 31 views
5

Tôi luôn nghĩ rằng hàm tạo ngầm trong C++ chỉ có thể là một hàm tạo với chỉ một đối số. Ví dụ:Đối số hàm dựng ngầm Implicit

class Foo1 
{ 
    Foo(int); // This could be an implicit constructor 
}; 

Nhưng là đoạn mã sau đúng:

class Foo2 
{ 
    Foo2(int, int=0); // Would compiler use this as an implicit constructor? 
} 

tôi có thể làm điều này:

Foo1 obj; 
... 
obj = 5; 

gì về Foo2?

+0

Trình tạo nội dung rõ ràng có ý nghĩa khác. Những gì bạn đang nói về constructor với các đối số mặc định. – Mahesh

+0

@mahesh Tôi biết ý nghĩa của các nhà xây dựng rõ ràng và câu hỏi là một câu hỏi :) Được rồi, tôi sẽ điền nó với một ví dụ. – Ockonal

+4

Không ai trong số đó là các nhà xây dựng rõ ràng - chúng không được đánh dấu bằng từ khoá 'tường minh'. Bạn có nghĩa là * implicit * constructor? Nếu có, có, các hàm tạo có thể được gọi ngầm nếu các tham số n + 1 được gán các đối số mặc định. –

Trả lời

7

Đầu tiên, bất kỳ công cụ xây dựng nào đều có thể được đánh dấu explicit. Làm thế nào nhiều đối số nó có là không liên quan.

Bằng cách đó, bạn chỉ cần hiểu những gì explicit thực sự có nghĩa là. Nó chỉ có nghĩa là cách duy nhất mà nhà xây dựng có thể được gọi là khi bạn rõ ràng ghi rõ tên lớp:

struct foo 
{ 
    foo(int){} 
    explicit foo(double){} 
}; 

void bar(foo){} 

bar(5); // okay, calls foo(int) to construct the foo 
bar(3.14); // error, cannot call foo(double) because foo was not explicitly used 
bar(foo(3.14)); // okay, calls foo(double) to construct the foo 

Lý do chúng tôi không đánh dấu nhà xây dựng nhiều lập luận rõ ràng là bởi vì nó vô dụng. Given:

struct baz 
{ 
    baz(int, int, int); 
}; 

Làm cách nào khác bạn có thể gọi hàm tạo khác ngoài nói baz? (Như trong baz(1, 2, 3).) †

Trong ví dụ của bạn, explicit sẽ hợp lý vì bạn có thể gọi hàm tạo đó chỉ với một đối số. Những gì bạn thực sự làm chỉ phụ thuộc vào nếu bạn cảm thấy nó nên được ngầm chuyển đổi hay không.


† Việc này bỏ qua danh sách khởi tạo C++ 11. Trong C++ 11, tôi nghĩ rằng bạn có thể nói:

void qaz(baz) {} 

qaz({1, 2, 3}); 

Và quản lý để có được một chuyển đổi ngầm để một constructor nhiều tranh cãi, nhưng tôi không biết đủ về initializer-danh sách để thực hiện một bình luận có ý nghĩa trừ dưới dạng chú thích cuối trang.

+0

Tôi luôn đánh dấu tất cả các hàm xây dựng 'rõ ràng', vì hai lý do: đối xứng và cơ hội một ngày nào đó một số lập trình viên có thể quyết định rằng tất cả trừ đối số đầu tiên có thể sử dụng một số giá trị mặc định và thêm nó. (Ngoại trừ các ctors mà tôi thực sự * muốn * để thực hiện các chuyển đổi ngầm, tất nhiên là tôi hầu như không bao giờ làm) –

+1

@PaulGroke: Làm cho tất cả các hàm xây dựng 'tường minh' là không cần thiết. Chỉ những người có một đối số, là những gì tôi nghĩ cần phải được đánh dấu là 'tường minh'. – Nawaz

+1

@Nawaz: Tôi biết rằng nó không cần thiết, và thẳng thắn mà nói, tôi không chắc làm thế nào bạn có thể hiểu sai ý kiến ​​của tôi để đi đến kết luận rằng tôi sẽ không. –

2

Nếu tôi hiểu những gì bạn đang yêu cầu, thì câu trả lời là có.

Cụ thể hơn, về cơ bản bất kỳ số điện thoại ctor nào có thể được gọi với chỉ một đối số có thể và sẽ được sử dụng cho chuyển đổi tiềm ẩn. Để ngăn chặn điều đó, ctor như vậy có thể được đánh dấu explicit. Điều đó áp dụng như nhau cho một ctor mà chỉ mất một đối số, hoặc một mà có thể mất nhiều hơn một đối số, nhưng cung cấp giá trị mặc định cho các đối số khác.

1

Bạn đang bối rối rõ ràng và tiềm ẩn ở đây. Những gì bạn đang nói về là các nhà xây dựng chuyển đổi. Một hàm tạo rõ ràng chỉ ngược lại: một hàm có thể không phải là được sử dụng cho các chuyển đổi (ẩn).

Và để trả lời câu hỏi của bạn: yes, Foo2(int, int=0) là một constructor chuyển đổi cho phép chuyển đổi ngầm như trong obj = 5, becaust nó có thể được gọi với một int tranh cãi.

Điều tương tự cũng xảy ra đối với các nhà xây dựng mặc định: nếu bạn thêm giá trị mặc định cho tham số đầu tiên, nó cũng sẽ trở thành hàm tạo mặc định.

1

Điều bạn có thể có nghĩa là ngầm định nhà thầu, không phải rõ ràng.

Dù sao, bạn không thể làm điều này (như trái ngược với những gì bạn nghĩ rằng bạn có thể):

Foo1 obj; //this line will not compile as it takes one argument! 
obj = 5; 

tôi chắc chắn rằng bạn đã không được biên dịch mã của bạn trước khi nói bạn không thể làm điều này.

Tuy nhiên, nếu bạn có nghĩa này,

Foo1 obj(10); //OK now 
obj = 5; 

Sau đó có, bạn có thể.

Bây giờ, làm thế nào về Foo2? Vâng, you can do so trong trường hợp của Foo2 là tốt:

Foo2 foo(10); 
foo = 5; 
+1

Cảm ơn bạn đã tìm mẹo về lỗi biên dịch. – Ockonal

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