Câu hỏi Từ khóa rõ ràng có ý nghĩa gì?


Cái gì explicit từ khóa có nghĩa là trong C + +?


2371
2017-09-23 13:58


gốc


Tôi chỉ muốn chỉ ra cho bất kỳ ai mới đến từ đó kể từ khi C ++ 11, explicit có thể được áp dụng cho nhiều hơn là chỉ các nhà xây dựng. Nó bây giờ là hợp lệ khi áp dụng cho các nhà khai thác chuyển đổi là tốt. Giả sử bạn có một lớp học BigInt với toán tử chuyển đổi int và một toán tử chuyển đổi rõ ràng std::string vì lý do gì. Bạn sẽ có thể nói int i = myBigInt;, nhưng bạn sẽ phải đúc một cách rõ ràng (sử dụng static_cast, tốt hơn) để nói std::string s = myBigInt;. - chris
Không thể rõ ràng cũng đề cập đến nhiệm vụ? (I E. int x(5);) - Eitan Myron
theunixshell.blogspot.com/2013/01/explicit-keyword-in-c.html - Vijay
@chris Ý tưởng về một chuyển đổi tiềm ẩn rõ ràng là vô lý. Hãy tránh nó! - curiousguy
@curiousguy, Không có điều gì như là một chuyển đổi ngầm rõ ràng. - chris


Các câu trả lời:


Trình biên dịch được phép tạo một chuyển đổi ngầm định để giải quyết các tham số cho một hàm. Điều này có nghĩa là trình biên dịch có thể sử dụng các hàm tạo có thể gọi với tham số đơn để chuyển đổi từ kiểu này sang kiểu khác để lấy đúng loại cho tham số.

Dưới đây là một lớp mẫu với một hàm tạo có thể được sử dụng cho các chuyển đổi ngầm:

class Foo
{
public:
  // single parameter constructor, can be used as an implicit conversion
  Foo (int foo) : m_foo (foo) 
  {
  }

  int GetFoo () { return m_foo; }

private:
  int m_foo;
};

Đây là một hàm đơn giản Foo vật:

void DoBar (Foo foo)
{
  int i = foo.GetFoo ();
}

và đây là nơi DoBar chức năng được gọi.

int main ()
{
  DoBar (42);
}

Đối số không phải là một Foo đối tượng, nhưng int. Tuy nhiên, có tồn tại một hàm tạo cho Foo mất một int do đó, hàm tạo này có thể được sử dụng để chuyển đổi tham số thành kiểu đúng.

Trình biên dịch được phép thực hiện điều này một lần cho mỗi tham số.

Tiền tố explicit từ khóa cho hàm tạo ngăn cản trình biên dịch sử dụng hàm tạo đó cho các chuyển đổi ngầm định. Thêm nó vào lớp trên sẽ tạo ra một lỗi trình biên dịch tại cuộc gọi hàm DoBar (42). Hiện tại, cần phải gọi cho chuyển đổi một cách rõ ràng với DoBar (Foo (42))

Lý do bạn có thể muốn làm điều này là tránh xây dựng tình cờ có thể ẩn các lỗi. Ví dụ:

  • Bạn có một MyString(int size) lớp với một hàm tạo xây dựng một chuỗi có kích thước đã cho. Bạn có một chức năng print(const MyString&)và bạn gọi print(3) (khi bạn thực ra dự định gọi print("3")). Bạn mong đợi nó in "3", nhưng nó in một chuỗi rỗng có độ dài 3 thay thế.

2755
2017-09-23 14:09



viết tốt, bạn có thể muốn đề cập đến các ccs đa arg với các tham số mặc định cũng có thể hoạt động như một ctor arg đơn, ví dụ, Object (const char * name = NULL, int otype = 0). - maccullt
Tôi nghĩ rằng nó cũng nên được đề cập rằng một trong những nên xem xét làm cho các nhà thầu đối số duy nhất rõ ràng ban đầu (nhiều hơn hoặc ít hơn tự động), và loại bỏ các từ khóa rõ ràng chỉ khi chuyển đổi tiềm ẩn là muốn thiết kế bởi. Tôi nghĩ rằng các contructors nên được mặc định theo mặc định với một từ khóa 'ngầm' để cho phép chúng hoạt động như các chuyển đổi ngầm định. Nhưng đó không phải là nó như thế nào. - Michael Burr
@thecoshman: Bạn không khai báo tham số  explicit - bạn khai báo constructor  explicit. Nhưng có: thông số của bạn về loại Foo phải được xây dựng explicitely, chúng sẽ không được xây dựng âm thầm bởi chỉ cần cắm các tham số của hàm khởi tạo của chúng vào hàm. - Christian Severin
Chỉ cần một FYI rằng khi gọi "print (3)" trong ví dụ của bạn, hàm cần phải là "print (const MyString &"). "Const" là bắt buộc ở đây vì 3 được chuyển thành đối tượng "MyString" tạm thời và bạn không thể liên kết tạm thời với tham chiếu trừ khi đó là "const" (khác trong danh sách dài của C ++ gotchas) - Larry
Vì lợi ích đầy đủ, tôi thêm rằng ngoài việc chuyển đổi tham số rõ ràng từ khóa ở đây cũng sẽ ngăn chặn việc sử dụng biểu mẫu chuyển nhượng của một ctor bản sao (ví dụ: Foo myFoo = 42;) và yêu cầu các biểu mẫu rõ ràng Foo myFoo = Foo (42); hoặc Foo myFoo (42); - Arbalest


Giả sử bạn có một lớp String:

class String {
public:
    String(int n); // allocate n bytes to the String object
    String(const char *p); // initializes object with char *p
};

Bây giờ, nếu bạn thử:

String mystring = 'x';

Nhân vật 'x' sẽ được chuyển đổi hoàn toàn thành int và sau đó String(int) constructor sẽ được gọi. Tuy nhiên, đây không phải là những gì người dùng có thể đã dự định. Vì vậy, để ngăn chặn các điều kiện như vậy, chúng ta sẽ định nghĩa hàm tạo như explicit:

class String {
public:
    explicit String (int n); //allocate n bytes
    String(const char *p); // initialize sobject with string p
};

964
2017-09-23 16:37



Và cần lưu ý rằng các quy tắc khởi tạo tổng quát mới của C ++ 0x sẽ làm cho String s = {0}; hình thành không đúng, thay vì cố gắng gọi cho hàm tạo khác bằng một con trỏ rỗng, như String s = 0; sẽ làm. - Johannes Schaub - litb
Mặc dù đây là một câu hỏi cũ có vẻ như đáng để chỉ ra một vài điều (hoặc có ai đó đặt tôi thẳng). Bằng cách tạo biểu mẫu int, hoặc cả hai ctors, 'explicit' bạn sẽ vẫn có cùng một lỗi nếu bạn sử dụng String mystring('x') khi bạn muốn nói String mystring("x") phải không? Ngoài ra, từ nhận xét ở trên, tôi thấy hành vi được cải thiện của String s = {0} kết thúc String s = 0 nhờ làm cho hình thức int của ctor 'rõ ràng'. Nhưng, ngoài việc biết được ưu tiên của các ctors, làm thế nào bạn biết được ý định (tức là làm thế nào để phát hiện ra lỗi) của điều này String s{0} ? - Arbalest
Tại sao String mystring = 'x'; đang chuyển đổi sang int? - InQusitive
@InQusitive: 'x'đang được coi là số nguyên vì char kiểu dữ liệu chỉ là một số nguyên 1 byte. - DavidRR
Vấn đề với ví dụ của bạn là nó chỉ hoạt động với sao chép khởi tạo (sử dụng =) nhưng không có khởi tạo trực tiếp (không sử dụng =): trình biên dịch sẽ vẫn gọi String(int) constructor mà không tạo ra lỗi nếu bạn viết String mystring('x');, như @Arbalest đã chỉ ra. Các explicit từ khóa có nghĩa là để ngăn chặn chuyển đổi tiềm ẩn xảy ra trong khởi tạo trực tiếp và giải quyết chức năng. Một giải pháp tốt hơn cho ví dụ của bạn sẽ là quá tải đơn giản của hàm tạo: String(char c);. - Maggyero


Trong C ++, một hàm tạo chỉ với một tham số bắt buộc được xem là hàm chuyển đổi ngầm định. Nó chuyển đổi kiểu tham số thành kiểu lớp. Cho dù đây là một điều tốt hay không phụ thuộc vào ngữ nghĩa của các nhà xây dựng.

Ví dụ, nếu bạn có một lớp chuỗi với hàm tạo String(const char* s), đó có thể là chính xác những gì bạn muốn. Bạn có thể vượt qua const char* với một hàm mong đợi một Stringvà trình biên dịch sẽ tự động xây dựng tạm thời String đối tượng cho bạn.

Mặt khác, nếu bạn có một lớp đệm có hàm tạo Buffer(int size) lấy kích thước của bộ đệm theo byte, có thể bạn không muốn trình biên dịch biến một cách lặng lẽ intvào BufferS. Để ngăn chặn điều đó, bạn khai báo hàm tạo với explicit từ khóa:

class Buffer { explicit Buffer(int size); ... }

Bằng cách đó,

void useBuffer(Buffer& buf);
useBuffer(4);

trở thành lỗi biên dịch. Nếu bạn muốn vượt qua tạm thời Buffer đối tượng, bạn phải làm như vậy một cách rõ ràng:

useBuffer(Buffer(4));

Tóm lại, nếu hàm tạo tham số đơn của bạn chuyển đổi tham số thành đối tượng của lớp, bạn có thể không muốn sử dụng explicit từ khóa. Nhưng nếu bạn có một hàm tạo chỉ đơn giản xảy ra để lấy một tham số, bạn nên khai báo nó như là explicitđể ngăn trình biên dịch gây bất ngờ cho bạn với các chuyển đổi không mong muốn.


130
2017-10-08 14:43



useBuffer mong đợi một lvalue cho lập luận của mình, useBuffer(Buffer(4)) sẽ không hoạt động vì nó. Thay đổi nó để có một const Buffer& hoặc là Buffer&& hoặc chỉ Buffer sẽ làm cho nó hoạt động. - pqnet


Câu trả lời này là về việc tạo đối tượng có / không có một hàm tạo rõ ràng vì nó không nằm trong các câu trả lời khác.

Hãy xem xét lớp sau mà không có một hàm tạo rõ ràng:

class Foo
{
public:
    Foo(int x) : m_x(x)
    {
    }

private:
    int m_x;
};

Các đối tượng của lớp Foo có thể được tạo theo 2 cách:

Foo bar1(10);

Foo bar2 = 20;

Tùy thuộc vào việc thực hiện, cách thứ hai của instantiating class Foo có thể gây nhầm lẫn, hoặc không phải là những gì các lập trình viên dự định. Tiền tố explicit từ khóa cho hàm tạo sẽ tạo ra lỗi trình biên dịch tại Foo bar2 = 20;.

Nó là thông thường thực hành tốt để khai báo các hàm tạo đơn đối số là explicit, trừ khi việc triển khai của bạn đặc biệt nghiêm cấm nó.

Cũng lưu ý rằng các nhà xây dựng với

  • đối số mặc định cho tất cả các tham số hoặc
  • đối số mặc định cho tham số thứ hai trở đi

cả hai có thể được sử dụng như các hàm tạo đối số đơn. Vì vậy, bạn có thể muốn làm những thứ này explicit.

Một ví dụ khi bạn cố ý không phải muốn làm cho hàm tạo đối số đơn của bạn rõ ràng là nếu bạn đang tạo một hàm functor (hãy xem cấu trúc 'add_x' struct được khai báo trong điều này câu trả lời). Trong trường hợp này, tạo một đối tượng add_x add30 = 30; có lẽ sẽ có ý nghĩa.

Đây là viết tốt về các nhà xây dựng rõ ràng.


34
2017-11-21 02:36





Các explicit từ khóa tạo một hàm tạo chuyển đổi cho hàm tạo không chuyển đổi. Kết quả là, mã ít bị lỗi hơn.


31
2017-07-10 23:48



câu trả lời thẳng nếu bạn biết c ++, nếu bạn không, bạn có thể đi đến câu trả lời của cjm ... - n611x007


Từ khóa explicit đi cùng

  • một hàm tạo của lớp X không thể được sử dụng để chuyển đổi hoàn toàn tham số đầu tiên (chỉ bất kỳ) thành kiểu X

C ++ [class.conv.ctor]

1) Một hàm khởi tạo được khai báo mà không có hàm rõ ràng của hàm-specifier chỉ định một chuyển đổi từ các kiểu tham số của nó thành kiểu của lớp của nó. Một hàm tạo như vậy được gọi là một hàm tạo chuyển đổi.

2) Một hàm tạo rõ ràng xây dựng các đối tượng giống như các hàm tạo không rõ ràng, nhưng chỉ làm như vậy khi cú pháp khởi tạo trực tiếp (8.5) hoặc nơi các phôi (5.2.9, 5.4) được sử dụng một cách rõ ràng. Một hàm tạo mặc định có thể là một hàm tạo rõ ràng; một hàm tạo như vậy sẽ được sử dụng để thực hiện khởi tạo mặc định hoặc valueinitialization   (8.5).

  • hoặc một hàm chuyển đổi chỉ được xem xét để khởi tạo trực tiếp và chuyển đổi rõ ràng.

C ++ [class.conv.fct]

2) Một hàm chuyển đổi có thể rõ ràng (7.1.2), trong trường hợp đó nó chỉ được coi là chuyển đổi do người dùng định nghĩa để khởi tạo trực tiếp (8.5). Nếu không, chuyển đổi do người dùng xác định không bị hạn chế sử dụng trong các bài tập   và khởi tạo.

Tổng quan

Chỉ có thể sử dụng các hàm chuyển đổi rõ ràng và hàm tạo cho các chuyển đổi rõ ràng (khởi tạo trực tiếp hoặc hoạt động truyền rõ ràng) trong khi các hàm tạo và chuyển đổi không rõ ràng có thể được sử dụng cho các chuyển đổi rõ ràng cũng như rõ ràng.

/*
                                 explicit conversion          implicit conversion

 explicit constructor                    yes                          no

 constructor                             yes                          yes

 explicit conversion function            yes                          no

 conversion function                     yes                          yes

*/

Ví dụ sử dụng cấu trúc X, Y, Z và chức năng foo, bar, baz:

Hãy xem xét một thiết lập nhỏ các cấu trúc và chức năng để thấy sự khác biệt giữa explicitvà khôngexplicit chuyển đổi.

struct Z { };

struct X { 
  explicit X(int a); // X can be constructed from int explicitly
  explicit operator Z (); // X can be converted to Z explicitly
};

struct Y{
  Y(int a); // int can be implicitly converted to Y
  operator Z (); // Y can be implicitly converted to Z
};

void foo(X x) { }
void bar(Y y) { }
void baz(Z z) { }

Ví dụ về hàm tạo:

Chuyển đổi đối số hàm:

foo(2);                     // error: no implicit conversion int to X possible
foo(X(2));                  // OK: direct initialization: explicit conversion
foo(static_cast<X>(2));     // OK: explicit conversion

bar(2);                     // OK: implicit conversion via Y(int) 
bar(Y(2));                  // OK: direct initialization
bar(static_cast<Y>(2));     // OK: explicit conversion

Khởi tạo đối tượng:

X x2 = 2;                   // error: no implicit conversion int to X possible
X x3(2);                    // OK: direct initialization
X x4 = X(2);                // OK: direct initialization
X x5 = static_cast<X>(2);   // OK: explicit conversion 

Y y2 = 2;                   // OK: implicit conversion via Y(int)
Y y3(2);                    // OK: direct initialization
Y y4 = Y(2);                // OK: direct initialization
Y y5 = static_cast<Y>(2);   // OK: explicit conversion

Ví dụ về hàm chuyển đổi:

X x1{ 0 };
Y y1{ 0 };

Chuyển đổi đối số hàm:

baz(x1);                    // error: X not implicitly convertible to Z
baz(Z(x1));                 // OK: explicit initialization
baz(static_cast<Z>(x1));    // OK: explicit conversion

baz(y1);                    // OK: implicit conversion via Y::operator Z()
baz(Z(y1));                 // OK: direct initialization
baz(static_cast<Z>(y1));    // OK: explicit conversion

Khởi tạo đối tượng:

Z z1 = x1;                  // error: X not implicitly convertible to Z
Z z2(x1);                   // OK: explicit initialization
Z z3 = Z(x1);               // OK: explicit initialization
Z z4 = static_cast<Z>(x1);  // OK: explicit conversion

Z z1 = y1;                  // OK: implicit conversion via Y::operator Z()
Z z2(y1);                   // OK: direct initialization
Z z3 = Z(y1);               // OK: direct initialization
Z z4 = static_cast<Z>(y1);  // OK: explicit conversion

Tại sao sử dụng explicit hàm chuyển đổi hoặc hàm tạo?

Các nhà xây dựng chuyển đổi và các hàm chuyển đổi không rõ ràng có thể giới thiệu sự mơ hồ.

Xem xét cấu trúc V, có thể chuyển đổi thành int, một cấu trúc U hoàn toàn có thể xây dựng từ V và một hàm f quá tải cho U và bool tương ứng.

struct V {
  operator bool() const { return true; }
};

struct U { U(V) { } };

void f(U) { }
void f(bool) {  }

Cuộc gọi đến f là mơ hồ nếu đi qua một đối tượng thuộc loại V.

V x;
f(x);  // error: call of overloaded 'f(V&)' is ambiguous

Trình biên dịch không biết thời tiết để sử dụng hàm tạo U hoặc hàm chuyển đổi để chuyển đổi V đối tượng thành loại để chuyển đến f.

Nếu một trong hai hàm tạo của U hoặc chức năng chuyển đổi của V sẽ là explicit, sẽ không có sự mơ hồ vì chỉ chuyển đổi không rõ ràng mới được xem xét. Nếu cả hai rõ ràng là cuộc gọi đến f sử dụng một đối tượng kiểu V sẽ phải được thực hiện bằng cách sử dụng một chuyển đổi rõ ràng hoặc hoạt động đúc.

Các nhà xây dựng chuyển đổi và các hàm chuyển đổi không rõ ràng có thể dẫn đến hành vi không mong muốn.

Hãy xem xét chức năng in một số vector:

void print_intvector(std::vector<int> const &v) { for (int x : v) std::cout << x << '\n'; }

Nếu kích thước-constructor của vector sẽ không được rõ ràng nó sẽ có thể gọi các chức năng như thế này:

print_intvector(3);

Điều gì sẽ xảy ra với một cuộc gọi như vậy? Một dòng chứa 3 hoặc ba dòng chứa 0? (Trường hợp thứ hai là những gì xảy ra.)

Việc sử dụng từ khóa rõ ràng trong giao diện lớp sẽ buộc người dùng giao diện phải rõ ràng về một chuyển đổi mong muốn.

Như Bjarne Stroustrup đặt nó (trong "Ngôn ngữ lập trình C ++", 4th Ed., 35.2.1, trang 1011) về câu hỏi tại sao std::duration không thể được xây dựng ngầm từ một số đơn giản:

Nếu bạn biết những gì bạn có ý nghĩa, hãy rõ ràng về nó.


31
2018-05-14 09:28





Các explicit-keyword có thể được sử dụng để thực thi một hàm tạo được gọi là một cách rõ ràng.

class C{
public:
    explicit C(void) = default;
};

int main(void){
    C c();
    return 0;
}

các explicit-keyword ở phía trước của hàm tạo C(void) cho trình biên dịch biết rằng chỉ gọi rõ ràng đến hàm tạo này được cho phép.

Các explicit-keyword cũng có thể được sử dụng trong các toán tử tạo kiểu do người dùng định nghĩa:

class C{
public:
    explicit inline operator bool(void) const{
        return true;
    }
};

int main(void){
    C c;
    bool b = static_cast<bool>(c);
    return 0;
}

Đây, explicit-keyword chỉ thực thi các lệnh rõ ràng để hợp lệ, vì vậy bool b = c; sẽ là một diễn viên không hợp lệ trong trường hợp này. Trong những tình huống như thế này explicit-keyword có thể giúp lập trình viên để tránh ẩn, phôi không mong muốn. Cách sử dụng này đã được chuẩn hóa trong C ++ 11.


25
2017-10-01 22:00



C c(); trong ví dụ đầu tiên không có nghĩa là bạn nghĩ nó có nghĩa là gì: đó là tuyên bố của một hàm có tên c không có tham số và trả về một thể hiện C. - 6502
explicit operator bool() cũng là phiên bản C ++ 11 của bool an toàn và có thể được sử dụng ngầm trong kiểm tra điều kiện (và chỉ có trong tình trạng kiểm tra, theo như tôi biết). Trong ví dụ thứ hai của bạn, dòng này cũng sẽ hợp lệ trong main(): if (c) { std::cout << "'c' is valid." << std:: endl; }. Ngoài ra, mặc dù, nó không thể được sử dụng mà không cần đúc rõ ràng. - Justin Time
"constructor được gọi một cách rõ ràng"không - curiousguy
@JustinTime Đó là một phiên bản bị hỏng, bẻ gãy của bool an toàn. Toàn bộ ý tưởng về chuyển đổi ngầm định rõ ràng là vô lý. - curiousguy
@curiousguy Đúng. Nó có vẻ hơi giống như một kludge, nhằm dễ nhớ hơn (có khả năng hy vọng rằng dịch được sử dụng thường xuyên) hơn là theo logic tiếng Anh, và được thiết kế để không hoàn toàn không tương thích với các triển khai bool an toàn trước đây (vì vậy bạn ít có khả năng phá vỡ một cái gì đó nếu bạn trao đổi nó trong). IMO, ít nhất. - Justin Time


Điều này đã được thảo luận (constructor rõ ràng là gì). Nhưng tôi phải nói, rằng nó thiếu các mô tả chi tiết được tìm thấy ở đây.

Bên cạnh đó, nó luôn luôn là một thực hành mã hóa tốt để làm cho một nhà thầu đối số của bạn (bao gồm cả những người có giá trị mặc định cho arg2, arg3, ...) như đã nêu. Giống như luôn luôn với C ++: nếu bạn không - bạn sẽ muốn bạn đã làm ...

Một thực hành tốt khác cho các lớp học là tạo bản sao và gán riêng tư (a.k.a. vô hiệu hóa nó) trừ khi bạn thực sự cần phải thực hiện nó. Điều này tránh được các bản sao cuối cùng của con trỏ khi sử dụng các phương thức mà C ++ sẽ tạo cho bạn theo mặc định. Một cách khác để làm điều này là lấy được từ boost :: noncopyable.


17
2017-08-20 12:45



Bài đăng này được viết vào năm 2009. Hôm nay bạn không tuyên bố chúng là riêng tư, nhưng đúng hơn là nói = delete. - v010dya
@fmuecke liên kết đã chết, câu hỏi đã bị xóa - David Cabrera


Tham chiếu Cpp luôn hữu ích !!! Có thể tìm thấy chi tiết về trình chỉ định rõ ràng đây. Bạn có thể cần phải xem xét chuyển đổi ngầm và sao chép-khởi tạo quá.

Cái nhìn lướt qua

Trình chỉ định rõ ràng chỉ định rằng hàm tạo hoặc hàm chuyển đổi (kể từ C ++ 11) không cho phép chuyển đổi ngầm hoặc sao chép-khởi tạo.

Ví dụ như sau:

struct A
{
    A(int) { }      // converting constructor
    A(int, int) { } // converting constructor (C++11)
    operator bool() const { return true; }
};

struct B
{
    explicit B(int) { }
    explicit B(int, int) { }
    explicit operator bool() const { return true; }
};

int main()
{
    A a1 = 1;      // OK: copy-initialization selects A::A(int)
    A a2(2);       // OK: direct-initialization selects A::A(int)
    A a3 {4, 5};   // OK: direct-list-initialization selects A::A(int, int)
    A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
    A a5 = (A)1;   // OK: explicit cast performs static_cast
    if (a1) cout << "true" << endl; // OK: A::operator bool()
    bool na1 = a1; // OK: copy-initialization selects A::operator bool()
    bool na2 = static_cast<bool>(a1); // OK: static_cast performs direct-initialization

//  B b1 = 1;      // error: copy-initialization does not consider B::B(int)
    B b2(2);       // OK: direct-initialization selects B::B(int)
    B b3 {4, 5};   // OK: direct-list-initialization selects B::B(int, int)
//  B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int,int)
    B b5 = (B)1;   // OK: explicit cast performs static_cast
    if (b5) cout << "true" << endl; // OK: B::operator bool()
//  bool nb1 = b2; // error: copy-initialization does not consider B::operator bool()
    bool nb2 = static_cast<bool>(b2); // OK: static_cast performs direct-initialization
}

15
2017-12-20 12:19



Vâng! Nghiên cứu ví dụ và mô tả về từ khóa trên cppreference là cách tốt nhất để hiểu explicit Tôi nghĩ. - dekuShrub
explicit operator bool() so với if là một trường hợp đặc biệt. Không có cách nào để tái tạo nó với người dùng được xác định Bool, explicit operator Bool() và một hàm gọi là If. - curiousguy


Các nhà xây dựng chuyển đổi rõ ràng (chỉ có C ++)

Trình chỉ định hàm rõ ràng kiểm soát loại ngầm định không mong muốn   chuyển đổi. Nó chỉ có thể được sử dụng trong các khai báo của các nhà xây dựng   trong một tuyên bố lớp học. Ví dụ, ngoại trừ mặc định   constructor, các nhà xây dựng trong lớp sau là chuyển đổi   nhà thầu.

class A
{
public:
    A();
    A(int);
    A(const char*, int = 0);
};

Các khai báo sau là hợp pháp:

A c = 1;
A d = "Venditti";

Tuyên bố đầu tiên tương đương với A c = A( 1 );.

Nếu bạn khai báo hàm tạo của lớp explicit, các tuyên bố trước đó sẽ là bất hợp pháp.

Ví dụ: nếu bạn khai báo lớp là:

class A
{
public:
    explicit A();
    explicit A(int);
    explicit A(const char*, int = 0);
};

Bạn chỉ có thể gán các giá trị khớp với các giá trị của loại lớp.

Ví dụ, các câu sau đây là hợp pháp:

  A a1;
  A a2 = A(1);
  A a3(1);
  A a4 = A("Venditti");
  A* p = new A(1);
  A a5 = (A)1;
  A a6 = static_cast<A>(1);

9
2018-01-23 09:26