Điều này được giải thích rõ trong phần mà từ đó trích dẫn này được thực hiện. Tôi sẽ không diễn giải nó trọn vẹn, nhưng đây là một bản tóm tắt ngắn về nội dung của phần.
Trước hết, bạn cần phải hiểu các điều khoản sau: implicitly-declared
, implicitly-defined
, trivial
, non-trivial
và synthesized
(một thuật ngữ được sử dụng bởi Stanley Lippman, nhưng không được sử dụng trong tiêu chuẩn).
ngầm-tuyên bố
Một constructor là implicitly-declared
cho một lớp học nếu không có user-declared
constructor trong lớp này. Ví dụ, lớp này struct T { };
không khai báo bất kỳ hàm tạo nào, do đó trình biên dịch ngầm khai báo một hàm tạo mặc định. Mặt khác, lớp này struct T { T(int); };
khai báo một hàm tạo, do đó trình biên dịch sẽ không khai báo một hàm tạo ngầm mặc định. Bạn sẽ không thể tạo một thể hiện của T
mà không có tham số, trừ khi bạn xác định hàm tạo mặc định của riêng mình.
ngầm xác định
Một constructor implicitly-declared
là implicitly-defined
khi nó được sử dụng, ví dụ: khi một thể hiện được tạo ra không có tham số. Giả sử lớp sau struct T { };
, dòng T t;
sẽ kích hoạt định nghĩa của T::T()
. Nếu không, bạn sẽ có một lỗi linker vì constructor sẽ được khai báo nhưng không được định nghĩa. Tuy nhiên, một hàm tạo ngầm được xác định không nhất thiết phải có bất kỳ mã nào được liên kết với nó! Một hàm tạo mặc định là được tổng hợp (có nghĩa là một số mã được tạo cho nó) bởi trình biên dịch chỉ trong một số trường hợp nhất định.
constructor tầm thường
Một constructor implicitly-declared
mặc định là trivial
khi:
- lớp của nó không có chức năng ảo và không có lớp cơ sở ảo và
- lớp cơ sở của nó có
trivial
nhà thầu và
- tất cả thành viên không tĩnh của nó có
trivial
nhà thầu.
Trong trường hợp này, trình biên dịch mặc định không có gì để làm, vì vậy không có mã nào được tổng hợp cho nó. Ví dụ, trong đoạn mã sau
struct Trivial
{
int i;
char * pc;
};
int main()
{
Trivial t;
}
việc xây dựng t
không liên quan đến bất kỳ hoạt động (bạn có thể thấy rằng bằng cách nhìn vào lắp ráp tạo ra: không có constructor được gọi là xây dựng t
).
không tầm thường
Mặt khác, nếu lớp không đáp ứng được ba yêu cầu đã nêu ở trên, constructor implicitly-declared
mặc định của nó sẽ non-trivial
, có nghĩa là nó sẽ liên quan đến một số hoạt động mà phải được thực hiện để tôn trọng ngữ nghĩa ngôn ngữ. Trong trường hợp này, trình biên dịch sẽ synthesize
thực hiện hàm tạo thực hiện các thao tác này.
Ví dụ, hãy xem xét các lớp sau đây:
struct NonTrivial
{
virtual void foo();
};
Kể từ khi nó có một hàm thành viên ảo, constructor mặc định của nó phải đặt con trỏ bảng ảo với giá trị đúng (giả sử việc thực hiện sử dụng một phương pháp ảo bàn, tất nhiên).
Tương tự như vậy, các nhà xây dựng của lớp này
struct NonTrivial
{
std::string s;
};
phải gọi chuỗi constructor mặc định, vì nó không phải là trivial
. Để thực hiện các hoạt động này, trình biên dịch tạo mã cho hàm dựng mặc định và gọi nó bất cứ lúc nào bạn tạo một cá thể không có tham số. Bạn có thể kiểm tra điều này bằng cách nhìn vào assembly tương ứng với instantiation này NonTrivial n;
(bạn sẽ thấy một hàm call, trừ khi constructor đã được inlined).
Tóm tắt
Khi bạn không cung cấp bất kỳ constructor cho lớp học của bạn, trình biên dịch ngầm tuyên bố vỡ nợ một. Nếu bạn cố gắng sử dụng nó, trình biên dịch ngầm định nghĩa nó, nếu nó có thể (nó không phải lúc nào cũng có thể, ví dụ khi một lớp có một thành viên không cấu hình mặc định). Tuy nhiên, định nghĩa ngầm định này không hàm ý việc tạo ra bất kỳ mã nào. Trình biên dịch cần tạo mã cho hàm tạo (tổng hợp nó) chỉ khi nó không nhỏ, có nghĩa là nó liên quan đến các hoạt động nhất định cần thiết để thực hiện ngữ nghĩa ngôn ngữ.
N.B.
"Mô hình đối tượng bên trong C++ của Stanley B Lippman" và câu trả lời này đề cập đến (có thể) việc triển khai C++ chứ không phải ngữ nghĩa của nó. Kết quả là, không có điều nào ở trên có thể được tổng quát hóa cho tất cả các trình biên dịch: theo như tôi biết, việc triển khai thực hiện hoàn toàn được phép tạo mã ngay cả đối với một hàm tạo tầm thường. Từ quan điểm của người dùng C++, tất cả những gì quan trọng là khía cạnh "được khai báo rõ ràng/được định nghĩa" (và cũng là sự khác biệt tầm thường/không tầm thường, vì nó có một số hàm ý (ví dụ, một đối tượng của một lớp không tầm thường) nhà xây dựng không thể là một thành viên của một công đoàn))
Truy vấn chính xác là gì? – iammilind
AFAIK mọi lớp đều có hàm tạo mặc định, tuy nhiên tốt nhất bạn nên tạo nó (ít nhất là tôi làm nó). –
Và câu hỏi là ...? – PlasmaHH