Là một hàm tạo đối tượng của người Viking có phải là một tên ngắn hơn cho một hàm có tên `object` return type` object` không?


9

Ý tôi là, đó là vấn đề chọn từ nhiều hơn bất kỳ sự khác biệt nào giữa lệnh gọi hàm và hàm tạo. Thứ được đặt tên là "hàm tạo của một đối tượng" cũng có thể được đặt tên là "hàm với objectkiểu trả về tên object".

Người ta có thể lập luận rằng C ++ không cho phép một người có cùng chức năng và tên loại; tuy nhiên, có cách giải quyết để làm điều đó. C ++ có đường cú pháp đặc biệt (được đặt tên là hàm tạo) mà bạn có thể tạo một hàm với objectkiểu trả về tên object. Vì vậy, tôi nghĩ rằng một hàm tạo có thể được nhìn thấy và sử dụng như một hàm đứng miễn phí.

Có một số khác biệt ngữ nghĩa quan trọng tôi đang thiếu ở đây?


1
Lưu ý rằng thực tế là các hàm tạo được đặt tên theo kiểu của chúng không phải là phổ quát: PHP gọi chúng là __construct, Object Pascal / Delphi gọi chúng là Tạo - và tôi dường như nhớ rằng trong trường hợp đó chỉ là quy ước và sự khác biệt thực sự là chúng có từ khóa "constructor" trước định nghĩa của chúng.
IMSoP

Lưu ý: Các nhà xây dựng trong C ++ không trả về bất cứ điều gì (và do đó không có bất kỳ loại trả về nào).
el.pescado

bác sĩ là phương pháp meta, không phải phương pháp. bạn không gửi tin nhắn ctor đến một thể hiện của một lớp, bạn gửi nó đến lớp - thực sự đến đối tượng lớp, đó là đối tượng meta của lớp. và bác sĩ chắc chắn không phải là chức năng, vì chúng có tác dụng phụ - bạn nhận được một kết quả khác nhau mỗi lần.

Câu trả lời:


17

Một constructor về cơ bản là một phương thức, vâng, nhưng nó là một phương thức đặc biệt.

Ví dụ, trong C ++, hàm tạo không chỉ đơn giản là một hàm trả về một thể hiện mới của kiểu đó. Nếu đó là, thừa kế sẽ không hoạt động. Bạn không thể gọi vào các hàm tạo cơ sở, vì chúng cũng sẽ trả về một thể hiện mới. Bạn sẽ kết thúc với một thể hiện mới của A, sau đó được trả về hàm tạo của B, tạo ra một thể hiện mới của B, sau đó được trả về cho hàm tạo của C, v.v.

Thay vào đó, một constructor là một phương thức khởi tạo được phân bổ tự động gọi. Khi bạn nói, gọi "mới" để tạo một đối tượng trên heap, nó sẽ cấp phát bộ nhớ cho loại bạn đã yêu cầu (sử dụng bộ cấp phát bộ nhớ, như malloc), sau đó gọi phương thức constructor trên nó. Trình biên dịch có các quy tắc đặc biệt về cách thức và theo thứ tự nào, hàm tạo đó có thể gọi các hàm tạo khác. Ví dụ, trong C #, nếu bạn không gọi rõ ràng một hàm tạo cơ sở, trình biên dịch sẽ thêm một cuộc gọi đến hàm tạo mặc định cơ sở.

Đó là những quy tắc về cách trình biên dịch xử lý các hàm tạo làm cho nó khác với "một hàm có tên .ctor trả về một thể hiện của kiểu".


3
Bạn cũng thường không sử dụng newđể xây dựng các đối tượng trong C ++, vì nó có các biến tự động.
Quentin

6

Không, một hàm tạo objectrất khác với hàm được gọi objectvà trả về object. Một constructor không có tên, nhưng đó phần lớn là một kỹ thuật. Sự khác biệt quan trọng hơn là một hàm tạo không có kiểu trả về và nó không thể được gọi trực tiếp.

Một constructor không trả về bất cứ thứ gì vì nó được cung cấp một khối bộ nhớ và hoạt động trên bộ nhớ đó tại chỗ. Nó có thể hữu ích nếu bạn quên tên "constructor" trong giây lát và nghĩ về nó như là công cụ khởi tạo thay thế. Mục đích của nhà xây dựng không phải là để xây dựng một vật thể "ngoài không khí mỏng". Mục đích của nó là khởi tạo một đối tượng tại vị trí chính xác trong bộ nhớ mà nó cần.

Nếu một hàm tạo trả về một đối tượng, thì đối tượng trả về đó (giá trị trả về) sẽ phải sống ở đâu đó (có thể trên ngăn xếp), và ở đó, nó sẽ cần được khởi tạo bằng cách nào đó - chúng ta đang chạy vào một vòng lặp ở đây.

Điều này đi đôi với thực tế là một nhà xây dựng không bao giờ có thể được gọi trực tiếp. Nếu bạn có một lớp objectvà sử dụng một biểu thức object()ở đâu đó, thì nó không có ngữ nghĩa của "gọi hàm tạo của object." Nó có ngữ nghĩa của "tạo một đối tượng tạm thời của loại object." Trình biên dịch chuyển điều này thành phân bổ một số vị trí cho tạm thời để sống (có thể / thường là trên ngăn xếp) và gọi hàm tạo để xây dựng (= khởi tạo) một đối tượng ở vị trí đó.

Nguyên tắc tương tự áp dụng khi sử dụng new object(). Đây là một biểu thức mới, thực hiện hai điều:

  1. Gọi một hàm phân bổ operator new(trả về a void*) để cấp phát bộ nhớ thô cho đối tượng.
  2. Phát hành lệnh gọi hàm tạo trên bộ nhớ thô này để xây dựng (= khởi tạo) một đối tượng trong đoạn bộ nhớ thô đó.

Suy nghĩ của một nhà xây dựng objectnhư là một chức năng như thế này:

static object object();

sai. Nếu bất cứ điều gì, cách một nhà xây dựng làm việc gần hơn với điều này:

static void object(object &place_to_work_in);

Với ngoại lệ là bạn không bao giờ có thể gọi nó trực tiếp. Nó luôn chỉ được gọi khi được chỉ định bởi một cấu trúc ngôn ngữ khác. Ngay cả vị trí mới (còn được gọi là thủ thuật "gọi hàm tạo ở đây"), new (&place_for_object) object()không gọi trực tiếp hàm tạo. Nó chuyển thành một cuộc gọi đến hình thức vị trí mới trong operator newđó trả về đối số của nó, theo sau là một cuộc gọi đến hàm tạo (giống như bất kỳ biểu thức mới nào khác).


Tôi thú nhận rằng tôi không tham gia vào ngăn xếp này nhiều, vì vậy tôi có thể không quen thuộc với văn hóa và các tiêu chuẩn dự kiến ​​ở đây. Nếu có điều gì đó tôi có thể cải thiện câu trả lời này, xin vui lòng cho tôi biết ngoài việc hạ cấp, để tôi có thể sửa nó.
Angew không còn tự hào về SO

+1 Đừng lo lắng về downvote đó, câu trả lời của bạn rất tuyệt :) Vì một số lý do, hầu như tất cả các câu trả lời ở đây đều có một downvote.
amon

1

Nỗ lực của bạn trong việc viết lại là không chính xác.

Mặc dù một hàm tạo trông giống như một hàm thành viên có tên giống như tên của lớp, nhưng thực tế là hàm tạo không thực sự có tên. Điều này được quy định rõ ràng trong tiêu chuẩn C ++ (phần [class.ctor] / 1):

Nhà xây dựng không có tên.

Theo như: "Tôi nghĩ rằng một nhà xây dựng có thể được nhìn thấy và sử dụng như một chức năng đứng miễn phí" đi ... tốt, tôi không chắc ý của bạn là gì. Hàm miễn phí chắc chắn không thể là hàm tạo - hàm tạo phải là thành viên của lớp. Đồng thời, bạn chắc chắn có thể xác định một hàm miễn phí tạo ra một đối tượng và trả về một thể hiện của đối tượng đó. Hàm miễn phí đó thậm chí có thể có (cùng loại) có cùng tên với loại đối tượng mà nó tạo ra, nếu bạn muốn đủ tệ. Ví dụ: bạn có thể định nghĩa lớp bên trong một không gian tên, sau đó xác định một hàm bên ngoài không gian tên:

namespace foo { 
    class bar {};
}

foo::bar bar() { return foo::bar(); }

Đây thực sự không phải là cùng một tên (hàm chỉ barvà lớp là foo::bar), nhưng tùy thuộc vào quan điểm của bạn, bạn có thể sắp xếp chúng theo cách đó.

Một hàm miễn phí như vậy sẽ không có các đặc điểm chính khác của hàm tạo. Yêu cầu của một nhà xây dựng có thể hoàn toàn ẩn. Ví dụ: nếu tôi có một lớp như:

class foo {
public:
   foo (int) {}
   foo operator+(foo const &other) {}
};

... sau đó mã như:

foo f(1);

foo h(0);
h = f + 1;

... Có thể tạo một đối tượng foo tạm thời từ 1đó để nó có thể truyền đối tượng foo đó đến foo::operator+. Điều đó đơn giản sẽ không xảy ra với một hàm miễn phí, ngay cả khi hàm miễn phí đó được xác định để lấy đúng loại tham số và trả về loại kết quả được yêu cầu. Đối với một chuyển đổi ngầm định như vậy, cần có một hàm tạo.


1

Ý tôi là, đó là vấn đề chọn từ nhiều hơn bất kỳ sự khác biệt nào giữa lệnh gọi hàm và hàm tạo. Thứ được đặt tên là "constructor của một đối tượng" cũng có thể được đặt tên là "hàm với đối tượng loại trả về đối tượng".

Đầu tiên, các nhà xây dựng không trả lại bất cứ điều gì và do đó, không có kiểu trả về.

Thứ hai, các hàm tạo khác nhau ở chỗ bạn thực sự không thể gọi hàm tạo trực tiếp theo cách bạn gọi hàm. Thay vào đó, nếu bạn khai báo một biến, các hàm tạo thích hợp sẽ được gọi bởi bộ thực thi.

Thứ ba, trong trường hợp kế thừa, các hàm thông thường trong các lớp con ghi đè các hàm trong các lớp cha. Mặt khác, các hàm xây dựng, tầng - các hàm tạo của lớp cha được gọi đầu tiên, sau đó là các hàm tạo của lớp con.

Thứ tư, các nhà xây dựng có thể có danh sách khởi tạo, trong khi chức năng "bình thường" thì không thể.

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.