2009-03-06 49 views
13

Hãy lấy một ví dụ trong C#nhà xây dựng và Thừa kế

public class Foo 
{ 
    public Foo() { } 
    public Foo(int j) { } 
} 

public class Bar : Foo 
{ 

} 

Bây giờ, tất cả các thành viên của công chúng về Foo có thể truy cập tại Bar trừ các nhà xây dựng. Tôi không thể làm điều gì đó như

Bar bb = new Bar(1); 

Tại sao các nhà thầu không thể kế thừa?

CẬP NHẬT

Tôi hiểu chúng ta có thể constructors chuỗi, nhưng tôi muốn biết lý do tại sao các cấu trúc trên là không hợp lệ. Tôi chắc chắn phải có một lý do hợp lệ cho nó.

+0

trùng lặp của http://stackoverflow.com/questions/426484/why-are-constructors-not-inherited –

Trả lời

14

Các nhà xây dựng không thể kế thừa vì nó có thể gây ra hành vi kỳ lạ và không mong muốn. Cụ thể hơn, nếu bạn thêm một hàm tạo mới vào một lớp cơ sở, tất cả các lớp dẫn xuất sẽ nhận được một cá thể của hàm tạo đó. Đó là một điều xấu trong một số trường hợp, bởi vì có thể lớp cơ sở của bạn chỉ định các tham số không có ý nghĩa đối với các lớp dẫn xuất của bạn.

Một ví dụ phổ biến cho điều này là trong nhiều ngôn ngữ, lớp cơ sở cho tất cả các đối tượng (thường được gọi là "Đối tượng") có một hàm tạo không có tham số. Nếu các hàm tạo được kế thừa, điều này có nghĩa là tất cả các đối tượng đều có một hàm tạo tham số và không có cách nào để nói "Tôi muốn những người tạo ra một cá thể của lớp này để cung cấp các tham số X, Y và Z, nếu không mã của chúng sẽ không biên dịch. " Đối với nhiều lớp, điều quan trọng là các tham số nhất định phải được định nghĩa cho hàm thích hợp của chúng và làm cho các hàm tạo không thể di truyền là một phần của cách tác giả lớp có thể đảm bảo rằng một số tham số luôn được xác định.

Chỉnh sửa để trả lời nhận xét: Ramesh chỉ ra rằng nếu các nhà thầu được kế thừa như anh muốn, anh ta luôn có thể ghi đè các nhà xây dựng lớp cơ sở bằng cách sử dụng các hàm tạo riêng được khai báo trong mỗi lớp dẫn xuất. Điều đó chắc chắn đúng, nhưng có một vấn đề hậu cần với chiến lược này. Nó đòi hỏi các tác giả của các lớp dẫn xuất phải xem các lớp cơ sở chặt chẽ và thêm một hàm tạo riêng nếu chúng muốn khối thừa kế của hàm tạo lớp cơ sở. Không chỉ là rất nhiều công việc cho những người viết các lớp học có nguồn gốc, loại phụ thuộc ngầm này trên các lớp học chính xác là thứ có thể gây ra hành vi kỳ lạ.

Ramesh - không phải là những gì bạn mô tả sẽ không thể thêm vào ngôn ngữ. Nói chung nó không được thực hiện bởi vì loại hành vi có thể gây nhầm lẫn cho mọi người và dẫn đến rất nhiều gỡ lỗi và viết mã.

Quintin Robinson cung cấp một số câu trả lời rất đáng giá cho câu hỏi này trong các nhận xét chắc chắn đáng đọc.

+0

Nếu bạn thêm một hàm tạo vào lớp cơ sở, bạn có thể khởi tạo công cụ chỉ hiện diện trong lớp đó và đó là một hành vi tốt, tôi không thấy lý do tại sao bạn nói điều xấu của nó. – Ramesh

+0

Vì bạn có thể * yêu cầu * các thành viên không phải là cơ sở được khởi tạo trong lớp dẫn xuất của bạn. –

+0

@Simon - Nếu vậy, tôi luôn có thể ghi đè các hàm tạo của mình như các hàm – Ramesh

7

Họ là (thông qua chaining), bạn sẽ phải chuỗi các nhà xây dựng trong đối tượng có nguồn gốc của bạn .. IE:

public class Foo 
{ 
    public Foo() { } 
    public Foo(int j) { } 
} 

public class Bar : Foo 
{ 
    public Bar() : base() { } 
    public Bar(int j) : base(j) { } 
} 

Các nhà xây dựng trong các đối tượng có nguồn gốc sau đó sẽ chuỗi các cuộc gọi làm các nhà thầu tại các cơ sở các đối tượng.

This article cung cấp thêm một số ví dụ nếu bạn muốn đọc thêm.

+0

Tôi hiểu chuỗi, nhưng tại sao ví dụ của tôi không hợp lệ là những gì tôi muốn hiểu (tôi có đã cập nhật câu hỏi để làm nổi bật) – Ramesh

+0

Tôi thấy, xin lỗi vì đã trả lời câu hỏi mà bạn không hỏi Tôi nghĩ rằng tôi đã đọc được một chút quá xa. –

+0

Cảm ơn Quintin, câu hỏi của bạn đã khiến tôi suy nghĩ. +1 cho một trong các câu trả lời của bạn cho một câu hỏi khác. – Ramesh

0

Tôi nghĩ bạn có thể làm như sau:

public class Bar : Foo 
{ 
    public Bar (int i) 
    : base (i) 
    { 
    } 
} 

Tôi có thể là một chút tắt - nhưng đó là ý tưởng chung.

+0

Tôi hiểu chuỗi, nhưng tại sao ví dụ của tôi không hợp lệ là những gì tôi muốn hiểu (tôi đã cập nhật câu hỏi để làm nổi bật) – Ramesh

1

Nhà xây dựng không thể kế thừa vì lý do thiết kế. (Lưu ý rằng đây là tình huống tương tự trong mọi ngôn ngữ hướng đối tượng mà tôi biết.) Câu trả lời đơn giản là trong nhiều trường hợp bạn thực sự không muốn các nhà xây dựng tương tự như lớp cơ sở có sẵn. Xem this SO thread để biết thêm một số giải thích đầy đủ hơn.

0

Câu trả lời đơn giản là ngôn ngữ không hoạt động theo cách đó.

Câu hỏi thực sự bạn đang hỏi mặc dù là tại sao nó không hoạt động theo cách đó :-) Vâng, đó là một sự lựa chọn tùy ý, và nó tiếp tục từ C++ và Java (và rất có thể nhiều langauges khác ảnh hưởng đến C#) .

Lý do có thể là trình biên dịch sẽ chỉ tạo ra một hàm tạo không nhận đối số và chỉ cần gọi cha mẹ là nếu bạn muốn nhiều hơn những gì trình biên dịch làm cho bạn tự làm. Đây là sự lựa chọn tốt nhất vì tỷ lệ cược là bạn làm nhiều hơn suply gọi hàm tạo con.

2

Một lý do tại sao bạn có thể giới thiệu một hàm tạo vào một lớp là vì nó không có ý nghĩa để có một cá thể của lớp đó mà không có một "phụ thuộc" cụ thể. Ví dụ, nó có thể là một lớp truy cập dữ liệu mà đã có một kết nối đến một cơ sở dữ liệu:

public class FooRepository 
{ 
    public FooRepository(IDbConnection connection) { ... } 
} 

Nếu tất cả các nhà thầu nào từ các lớp cơ sở đã có sẵn, sau đó một người sử dụng của lớp kho của bạn sẽ có thể sử dụng constructor mặc định System.Object để tạo ra một thể hiện hợp lệ của lớp học của bạn:

var badRepository = new FooRepository(); 

Ẩn constructors thừa hưởng theo mặc định có nghĩa là bạn có thể thực thi phụ thuộc mà không lo lắng về người dùng tạo ra các trường hợp "không hợp lệ".

+0

+1 - Tôi hiểu các phương pháp không cần phải ẩn, nhưng người xây dựng cần phải vì lý do intialization. – Ramesh

1

Một số cuộc thảo luận

Ý tưởng cơ bản là để cung cấp kiểm soát càng nhiều để tác giả càng tốt. Và bạn có thể có căn cứ riêng. Làm thế nào bạn tạo ra các đối tượng sau đó?

2

Các constructor Foo chỉ có thể biết làm thế nào để khởi tạo một đối tượng Foo, vì vậy nó làm cho không có ý nghĩa rằng nó cũng nên biết làm thế nào để khởi tạo bất kỳ lớp con tiềm năng

public class Bar : Foo 
{ 
public Bar(int i) : base(i) { } 
} 

Câu chuyện các nhà xây dựng nói là: "Này cơ sở hãy làm bất cứ việc gì bạn cần làm để ở trạng thái tốt để tôi có thể tiếp tục và thiết lập chính mình một cách đúng đắn ".

2

Giả sử nhà thầu có thể kế thừa. Làm thế nào bạn sẽ vô hiệu hóa các nhà xây dựng kế thừa trong nhiều trường hợp là họ không có ý nghĩa đối với một lớp con?

Thay vì làm phức tạp ngôn ngữ với cơ chế chặn di sản thừa kế, nhà thiết kế ngôn ngữ đã chọn chỉ đơn giản là làm cho các nhà xây dựng không kế thừa được.

+0

+1 - Một trong những câu trả lời chính xác – Ramesh

+0

Làm thế nào để cung cấp rằng nếu một lớp con chứa bất kỳ hàm tạo nào, thì không có hàm tạo nào được thừa hưởng, nhưng nếu không thì tất cả đều là (có nghĩa là các nhà xây dựng sẽ được tạo tự động cho chuỗi. chữ ký)? Bất kỳ lớp nào không muốn "kế thừa" tất cả các nhà xây dựng của cha mẹ nó nên cung cấp ít nhất một lớp của riêng nó. Nếu cha mẹ không có một hàm tạo parameterless, sẽ không có ý nghĩa logic nào khác cho một lớp không có hàm tạo. – supercat

0

Thực sự, vì trình xây dựng gốc sẽ không khởi tạo đầy đủ đối tượng con.Một nhà xây dựng là một thứ cá nhân trong khía cạnh đó. Đó là lý do tại sao hầu hết các ngôn ngữ không kế thừa các nhà xây dựng.

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