Câu hỏi Tạo một thể hiện của lớp


Sự khác biệt giữa các dòng 1, 2, 3, 4 là gì?

Khi nào tôi sử dụng mỗi?

Tại sao dòng 3 in constructor Foo và dòng 7 trả về lỗi và dòng 8 không?

#include <iostream>     
using namespace std;

class Foo
 {
   public:
   Foo ( )
   {
      cout << "constructor Foo\n";
   }               
};

class Bar
 {
   public:
   Bar ( Foo )
   {
      cout << "constructor Bar\n";
   }
};

int main()
{
   /* 1 */ Foo* foo1 = new Foo ();
   /* 2 */ Foo* foo2 = new Foo;
   /* 3 */ Foo foo3;
   /* 4 */ Foo foo4 = Foo::Foo();

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );
   /* 6 */ Bar* bar2 = new Bar ( *new Foo );
   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );
   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

   return 1;
}

76
2017-09-03 13:18


gốc


Dù bạn làm gì, đừng làm *new Foo. Đó là một sự rò rỉ bộ nhớ tức thời. Tránh new trừ khi bạn thực sự thực sự cần nó. - R. Martinho Fernandes
trông có vẻ homeworky với tôi - Qnan
Tôi chỉ có một cuốn sách về C ++ và chủ đề này không được thảo luận trong đó ... - Kolyunya
Bạn nhận ra rằng bản chỉnh sửa của bạn đã trả về 2 câu trả lời lỗi thời, đúng không? Thêm vào đó, nó không hợp lệ ... 5 & 6 cung cấp những ví dụ hay về những gì không phải làm. Không tệ khi họ ở đó. - Luchian Grigore
@Kolyunya Nhận một cuốn sách khác. - Peter Wood


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


   /* 1 */ Foo* foo1 = new Foo ();

Tạo một đối tượng kiểu Foo trong bộ nhớ động. foo1 chỉ vào nó. Thông thường, bạn sẽ không sử dụng con trỏ thô trong C ++, mà là con trỏ thông minh. Nếu Foo là loại POD, điều này sẽ thực hiện khởi tạo giá trị (nó không áp dụng ở đây).

   /* 2 */ Foo* foo2 = new Foo;

Giống hệt trước, bởi vì Foo không phải là loại POD.

   /* 3 */ Foo foo3;

Tạo một Foo đối tượng được gọi foo3 trong bộ nhớ tự động.

   /* 4 */ Foo foo4 = Foo::Foo();

Sử dụng sao chép khởi tạo để tạo Foo đối tượng được gọi foo4 trong bộ nhớ tự động.

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );

Sử dụng Barchuyển đổi của nhà xây dựng để tạo ra một đối tượng của loại Bar trong lưu trữ động. bar1 là một con trỏ đến nó.

   /* 6 */ Bar* bar2 = new Bar ( *new Foo );

Giống như trước.

   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );

Đây chỉ là cú pháp không hợp lệ. Bạn không thể khai báo một biến ở đó.

   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

Sẽ làm việc và làm việc theo nguyên tắc tương tự với 5 và 6 nếu bar3 đã không được tuyên bố trong 7.

5 & ​​6 chứa rò rỉ bộ nhớ.

Cú pháp như new Bar ( Foo::Foo() ); không phải là bình thường. Nó luôn xảy ra new Bar ( (Foo()) ); - - thêm dấu ngoặc đơn tài khoản cho phân tích cú pháp vexing nhất. (đã sửa)


90
2017-09-03 13:24



Thực sự là Foo::Foo() thậm chí hợp pháp? Tôi nghĩ là không. - Konrad Rudolph
Cú pháp như thanh mới ( Foo::Foo() ); không phải là bình thường. Nó luôn xảy ra new Bar ( (Foo()) ); Nhưng các lớp HAI trong phạm vi này có một Foo phương pháp? - Kolyunya
Cách phân tích cú pháp khó chịu nhất không thể xảy ra trong new biểu hiện mặc dù;) - R. Martinho Fernandes
@KonradRudolph: Vâng, nó là hợp pháp. Ngôn ngữ xác định rằng tên của loại được tiêm vào định nghĩa của loại, do đó, bất kỳ số lượng lồng nhau Foo::Foo::..::Foo() sẽ giải quyết chính xác cùng một điều: Foo(). Đây là một trong những trường hợp đơn giản hóa ngôn ngữ lá để cho phép mã bí ẩn. - David Rodríguez - dribeas
@ Kolyunya: Tôi không hiểu bạn quan tâm, bạn có thể giải thích: HAI lớp học trong phạm vi này có Foo phương pháp?  Foo::Foo là cách gõ phức tạp Foo() đó là tên của một loại và một bộ ngoặc đơn. Chỉ có thể có một loại được trả về bằng tra cứu với một tên cụ thể - mặc dù có một hàm được tìm thấy bằng cách tra cứu có tên Foo trước khi lớp gặp phải, điều đó sẽ được gọi, nhưng đây là trực giao cho vấn đề ở bàn tay. - David Rodríguez - dribeas


  1. Phân bổ một số bộ nhớ động từ kho lưu trữ miễn phí và tạo một đối tượng trong bộ nhớ đó bằng cách sử dụng hàm tạo mặc định của nó. Bạn không bao giờ xóa nó, vì vậy bộ nhớ bị rò rỉ.
  2. Không chính xác giống như 1; trong trường hợp các loại do người dùng định nghĩa, các dấu ngoặc đơn là tùy chọn.
  3. Phân bổ một số bộ nhớ tự động và tạo một đối tượng trong bộ nhớ đó bằng cách sử dụng hàm tạo mặc định của nó. Bộ nhớ được giải phóng tự động khi đối tượng nằm ngoài phạm vi.
  4. Tương tự như 3. Vật lý, đối tượng được đặt tên foo4 được khởi tạo theo mặc định, xây dựng, sao chép và phá hủy một đối tượng tạm thời; thông thường, điều này được ưu tiên đưa ra kết quả tương tự như 3.
  5. Phân bổ một đối tượng động, sau đó khởi tạo một giây bằng cách sao chép đầu tiên. Cả hai đối tượng đều bị rò rỉ; và không có cách nào để xóa đầu tiên vì bạn không giữ con trỏ đến nó.
  6. Có chính xác giống như 5.
  7. Không biên dịch. Foo foo5 là một tuyên bố, không phải là một biểu thức; các đối số hàm (và hàm dựng) phải là các biểu thức.
  8. Tạo một đối tượng tạm thời và khởi tạo một đối tượng động bằng cách sao chép nó. Chỉ có đối tượng động bị rò rỉ; tạm thời bị hủy tự động ở cuối biểu thức đầy đủ. Lưu ý rằng bạn có thể tạo tạm thời chỉ với Foo() thay vì tương đương Foo::Foo() (hoặc thực sự Foo::Foo::Foo::Foo::Foo())

Khi nào tôi sử dụng mỗi?

  1. Đừng, trừ khi bạn thích trang trí không cần thiết trên mã của bạn.
  2. Khi bạn muốn tạo một đối tượng có thể vượt quá phạm vi hiện tại. Hãy nhớ xóa nó khi bạn đã hoàn thành nó và tìm hiểu cách sử dụng con trỏ thông minh để kiểm soát cuộc đời thuận tiện hơn.
  3. Khi bạn muốn một đối tượng chỉ tồn tại trong phạm vi hiện tại.
  4. Đừng, trừ khi bạn nghĩ rằng 3 trông nhàm chán và những gì để thêm một số trang trí không cần thiết.
  5. Không, bởi vì nó rò rỉ bộ nhớ mà không có cơ hội phục hồi.
  6. Không, bởi vì nó rò rỉ bộ nhớ mà không có cơ hội phục hồi.
  7. Đừng, bởi vì nó sẽ không biên dịch
  8. Khi bạn muốn tạo động Bar từ tạm thời Foo.

17
2017-09-03 14:19



1. Allocates some dynamic memory from the free store, and creates an object in that memory using its default constructor. You never delete it, so the memory is leaked. Tại sao tôi không bao giờ xóa nó? Tôi chỉ có thể gọi delete foo1 - Kolyunya
@ Kolyunya: Có, bạn có thể, và nên. Nhưng bạn không làm điều đó trong mã ví dụ của bạn, và tôi mặc dù nó đáng để chỉ ra điều đó. - Mike Seymour


Các dòng 1,2,3,4 sẽ gọi hàm tạo mặc định. Chúng khác nhau về bản chất vì 1,2 là đối tượng được tạo động và 3,4 là các đối tượng được tạo tĩnh.

Trong dòng 7, bạn tạo một đối tượng bên trong cuộc gọi đối số. Vì vậy, nó là một lỗi.

Và dòng 5 và 6 là lời mời rò rỉ bộ nhớ.


4
2017-09-03 13:25