2010-04-12 60 views
6

Tại sao tên của hàm tạo giống như tên lớp?các hàm tạo trong C++

+0

Vâng ... Tại sao không? Nói cách khác, không thể trả lời câu hỏi của bạn một cách có ý nghĩa cho đến khi bạn giải thích tại sao souch một câu hỏi thậm chí sẽ nảy sinh. – AnT

+0

@AndreyT: OP hỏi tại sao ngôn ngữ được thiết kế theo cách đó. Tôi nghĩ câu trả lời của Neil Butterworth chứng minh rằng một câu trả lời có ý nghĩa là có thể. – Cascabel

+0

@AndreyT: ví dụ: trong các trình tạo VB.NET, hãy sử dụng tên phương thức đặc biệt 'Mới'. Người ta có thể thấy điều này như làm cho mọi thứ rõ ràng hơn. Tôi khá chắc chắn tôi sẽ có khi tôi lần đầu tiên học C++. –

Trả lời

1

Vì đó là những gì đặc tả ngôn ngữ nói. Trong một số ngôn ngữ như Python nó không phải.

1

Đó chỉ là vấn đề về định nghĩa ngôn ngữ. Trình biên dịch biết rằng các phương thức có cùng tên là hàm tạo. Điều này cũng làm cho việc tạo ra các đối tượng của lớp đó rất rõ ràng, bất cứ ai mà không biết lớp biết rằng nếu tên bằng đây là hàm tạo.

5

Trong bản gốc "C có lớp", thực tế là không - nó được đặt tên là "mới", IIRC. Dù sao cho hầu hết các câu hỏi "tại sao" về C++, bạn có thể tìm thấy câu trả lời trong cuốn sách "Thiết kế và tiến hóa của C++".

10

Theo Stroustrup, vì thay thế một hàm mới "đã là một nguồn gây nhầm lẫn". Xem Thiết kế & Sự phát triển của C++, mục 3.11.2, mặc dù đó là sự biện minh đầy đủ mà tôi đã trích dẫn.

Chỉnh sửa: Như mọi người đã chỉ ra, có một số giải pháp thay thế. Ví dụ: Smalltalk, thực hiện điều này:

myclass new 

gửi thông báo "mới" đến đối tượng lớp myclass. Rõ ràng, giải pháp C++ ở đây sẽ hơi ngớ ngẩn:

myclass myclass 

không rõ ràng là hợp lý.

Delphi, OTOH, cho phép bất kỳ hàm có tên là một nhà xây dựng bằng cách gắn thẻ nó như vậy:

constructor Create; 
constructor FooBar; 

cả sẽ là tên constructor OK cho bất kỳ lớp. Như với Smalltalk, bạn cần phải gọi cho họ trên đối tượng lớp:

myclass.Create; 

Trong tất cả các giải pháp này, tôi nghĩ rằng C++ một người thanh lịch nhất, và tôi có thể thấy lý do tại sao nó đã gần như phổ biến thông qua ngôn ngữ người kế nhiệm .

+0

+1 Đây là điểm tôi đã cố gắng thực hiện ... nhưng điều này đi kèm với tài liệu. –

+0

@Justin: Tôi nghĩ câu trả lời của bạn bị chỉ trích một chút không công bằng - ý kiến ​​chỉ ra rằng trong tiêu chuẩn C++, không cần gọi tên hàm tạo, khi điểm chính xác là chuẩn được xác định cho phép nó hoạt động theo cách đó. – Cascabel

2

Nếu bạn muốn một hàm tạo gọi hàm khởi tạo của một lớp cơ sở làm khởi tạo, bạn sẽ cần phải chỉ định tên hàm khởi tạo của nó. Điều này sẽ rất khó khăn nếu chúng được đặt tên giống nhau. ví dụ.

class Animal { 
public: 
    Animal(); 
}; 

class Dog { 
public: 
    Dog(); 
}; 

Animal::Animal() { 
    // Base class constructor 
} 

Dog::Dog() : Animal() { 
    // Derived class constructor, calling the base constructor as an initializer 
} 
+0

'Chó :: Constructor(): Động vật :: Constructor() {}' –

+0

Tôi nói khó; nhưng không khả thi. Gladly, spec C++ không chọn cú pháp này. – spoulson

9

C++ chuẩn ngôn ngữ:

12,1. Các nhà xây dựng không có tên.

Câu hỏi của bạn dựa trên sự nhầm lẫn. Các nhà xây dựng sử dụng cú pháp khai báo đặc biệt, trong đó tên lớp được sử dụng một lần nữa thay cho tên thành viên. Tôi không thấy bất cứ điều gì sai trái với cú pháp đó, vì vậy tôi thậm chí không thể tưởng tượng những gì sẽ kích hoạt câu hỏi của bạn (mà làm cho nó khó khăn, nếu không phải là không thể trả lời).

Tuy nhiên, các nhà xây dựng trong C++ không có tên. Họ chỉ đơn giản là không cần tên, bởi vì bởi thiết kế không có ngữ cảnh trong C++, nơi bạn sẽ phải tham khảo một constructor.

3

Thực ra, nó không giống nhau. 12.1/1:

Constructors không có tên

Cách duy nhất để gọi một constructor đang sử dụng cú pháp xây dựng/chuyển đổi đối tượng cụ thể: nó không tìm thấy bằng cách tra cứu tên hàm, và bạn không thể lấy địa chỉ của một hàm tạo. Đây có lẽ là một điều tốt.

Tôi đoán rằng cú pháp cho tuyên bố một constructor có thể nhìn một cái gì đó như thế này:

struct Foo { 
    int a; 
    constructor(int a) : a(a) { } 
}; 

Nhưng điều đó sẽ đòi hỏi một từ dành riêng thêm, constructor. Nó có nghĩa là mã để khai báo một hàm tạo trông giống như mã để xây dựng một đối tượng. "Lợi ích" duy nhất sẽ là giải phóng "Foo" để sử dụng làm tên hàm thành viên. Điều đó nghe có vẻ không hữu ích đối với tôi, đặc biệt là vì bạn sẽ mất "hàm tạo" như một tên hàm thành viên. Nếu có bất kỳ sự phản đối nào đối với Foo như một tên hàm thành viên, tôi đoán nó có thể đạt được một cách khác nhau, ví dụ bằng cách sử dụng cú pháp hơi khác nhau để khai báo một hàm tạo (+ Foo, đi với ~ Foo, có thể?). Vì vậy, tôi đoán rằng không có.

Tôi không thể thấy ngay bất kỳ điểm nào trong việc có "hàm tạo tên người dùng" trong C++. Nếu bạn muốn có một hàm thành viên tĩnh của Foo mà mất một số thông số và trả về một Foo, bạn có thể khai báo nó như thế này:

struct Foo { 
    static Foo bar(int); 
}; 

và "sử dụng nó như là một nhà xây dựng" như thế này:

Foo f = Foo::bar(12); 
0

Các lựa chọn thay thế là gì? Có lẽ:

  • Invent một từ khóa mới để xác định một constructor như vậy
  • có một tên duy nhất cho tất cả các nhà xây dựng (như new()).

Cả hai tùy chọn này có vẻ kém hấp dẫn hơn so với thực tế.

+0

điều gì sai với một từ khóa mới để chỉ định một hàm tạo - giả sử rằng chúng ta đang nhìn chằm chằm với một ngôn ngữ mới? – sivabudh

+0

@ ShaChris23: Tôi rõ ràng đã không nói có bất cứ điều gì * sai * với ý tưởng, chỉ đơn thuần là giải pháp của C++ là chủ quan tốt hơn. Nếu từ khóa là * từ dành riêng * và không thể được sử dụng làm * số nhận dạng * (vì chúng ở trong C++), thì càng ít càng tốt. Giải pháp của C++ cho việc xác định hàm tạo nên một từ khóa hoàn toàn dư thừa. – Clifford

+0

Vâng, tôi đồng ý với những gì bạn nói. – sivabudh

0

Tôi giả định rằng bạn khá mới đối với C++ và thậm chí có thể lập trình hướng đối tượng. Vì vậy, trước tiên, tôi hy vọng bạn hiểu những gì một nhà xây dựng lớp học là.

Hầu hết các loại sẽ có hàm tạo của một số loại, được sử dụng để khởi tạo chính nó. Ngay cả khi nói về các nguyên thủy của int hoặc các loại biến khác, mọi thứ đều có thể được khởi tạo². Vì vậy, khi tạo lớp học, bạn được yêu cầu cung cấp bộ khởi tạo, được gọi là hàm xây dựng . Các nhà xây dựng có thể có các tham số có thể bắt buộc hay không. Chúng cũng có thể bị quá tải, có nghĩa là một lớp có thể có nhiều hàm tạo.

Kể từ khi nhà xây dựng là initializers cuộc gọi đến số đó là tiềm ẩn: một constructor lớp sẽ được gọi mỗi khi bạn tạo một đối tượng của lớp đó, có thể là bằng cách sử dụng từ khóa new hoặc bằng cách tuyên bố nó trên stack:

CMyObject obj; 

Bây giờ, chúng phải được khai báo bên trong lớp học của bạn. Họ là phương pháp, sau khi tất cả ... vì vậy, những gì nên được tên của nó? Python, ví dụ, có một cách tiếp cận khác và sử dụng một từ khóa, __init__ để làm như vậy; Nhà thiết kế của C++ đã quyết định rằng nó sẽ là tên của lớp.Sau khi tất cả, có một phương pháp thành viên với tên của lớp có thể gây ra xung đột tên (mơ hồ) dọc theo hệ thống. (Mặc dù this series bài viết là về C#, nó làm rõ lý do tại sao sử dụng tên cho thành viên của một phạm vi nhất định có cùng tên đó là xấu)

² Nhưng đôi khi chúng không phải để giảm chi phí thời gian thực hiện .

+0

Không chính xác khi nói rằng các nhà xây dựng là người khởi tạo là nguyên nhân khiến các cuộc gọi của họ bị ngầm định. Constructors là initializers trong Delphi, quá, ví dụ, nhưng các cuộc gọi cho họ là rõ ràng, và họ có thể có bất kỳ tên nào bạn muốn. –

0

Hàm tạo được gọi mỗi khi một đối tượng được tạo và điều này thường xảy ra tự động, tức là trình biên dịch gọi hàm khởi tạo là cuộc gọi hàm không có kiểu dữ liệu trả về. Do đó, ngôn ngữ C++ đã quyết định đặt tên cho hàm này là tên của lớp.

+1

Có gì với thư rác, eh? – GManNickG

+0

Phần sau "do đó" không làm theo một phần nào từ trước! – Clifford

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