2010-02-19 40 views
39

thể trùng lặp:
Why can’t I create an abstract constructor on an abstract C# class?Tóm tắt constructor trong C#

Tại sao tôi không thể khai báo trừu tượng một constructor của lớp học của tôi như thế này:

public abstract class MyClass { 
    public abstract MyClass(int param); 
} 
+3

Có vẻ như nhà xây dựng là một chi tiết triển khai và do đó buộc các lớp con được xây dựng theo một cách nhất định sẽ là một điều xấu. Nếu bạn muốn xây dựng gói gọn, hãy sử dụng mẫu nhà máy tĩnh. –

+0

Hình như anh ta muốn cái gì đó không thể với các genericss hiện tại, cấu trúc subtyping/parameter-taking constructor. – Dykam

+0

Bạn đang cố gắng đạt được điều gì? Có lẽ có một cách khác để nhìn vào nó. – fre0n

Trả lời

61

Trình xây dựng chỉ áp dụng cho lớp mà chúng được xác định, nghĩa là chúng không được kế thừa. Các hàm tạo lớp cơ sở được sử dụng (bạn phải gọi một trong số chúng, ngay cả khi chỉ gọi tự động mặc định) nhưng không bị ghi đè bởi các lớp khởi tạo. Bạn có thể định nghĩa một hàm tạo trên một lớp cơ sở trừu tượng - nó không thể được sử dụng trực tiếp, nhưng có thể được gọi bằng cách lấy ra các lớp. Những gì bạn không thể làm là bắt buộc một lớp dẫn xuất để thực hiện một chữ ký hàm tạo cụ thể.

Hoàn toàn hợp lý khi có một hàm tạo được định nghĩa, thường được bảo vệ, để xác định một số mã thiết lập chung cho tất cả các lớp dẫn xuất. Điều này đặc biệt đúng, có lẽ, khi lớp trừu tượng cung cấp một số hành vi mặc định khác dựa trên thiết lập này. Ví dụ:

public abstract class Foo 
{ 
    public string Name { get; private set; } 

    protected Foo(string name) 
    { 
     this.Name = name; 
    } 
} 

public class Bar : Foo 
{ 
    public Bar() : base("bar") 
    { 
     ... 
    } 
} 
+4

Bạn không sai, nhưng tôi sẽ làm rõ một điều: Constructors không được kế thừa, nhưng chúng * được * gọi là trẻ em. Lựa chọn duy nhất của bạn là * mà * constructor để chuỗi từ bạn. –

+0

Tôi đã cập nhật và làm rõ. – tvanfosson

+0

@tvanfosson: _bạn có thể có nghĩa là 'Bar' kế thừa' Foo'_ – comecme

12

Bạn có thể' t khai báo nó abstract, nhưng bạn có thể có một hàm tạo trên lớp trừu tượng của bạn; chỉ cần xóa từ abstract và cung cấp nội dung cho nó.

+14

... và cung cấp một cơ thể cho nó. – tvanfosson

+4

Nó cũng là một thực hành tốt để khai báo các nhà thầu trong các lớp trừu tượng như ** được bảo vệ **. Nó thực thi thực tế là lớp không thể được khởi tạo trực tiếp. –

+0

@tvanfosson: Cảm ơn bạn đã chỉ ra điều đó. Tôi đã bỏ lỡ điều đó khi tôi đọc câu hỏi. –

0

Theo định nghĩa, lớp không thể được khởi tạo trực tiếp, do đó, theo nghĩa nào đó, nó đã được trừu tượng.

+0

Phương pháp trừu tượng không có cơ thể cho đến khi nó được cung cấp bởi một lớp dẫn xuất. Điều này chắc chắn không đúng với các nhà xây dựng của các lớp trừu tượng. –

+0

Tôi thấy quan điểm của bạn. Tuy nhiên, ý định của câu hỏi có liên quan nhiều hơn đến thừa kế. –

1

Một hàm tạo không phải là phương pháp thông thường. Nó có một mục đích đặc biệt, và do đó bị giới hạn các tính năng ngôn ngữ có ý nghĩa cho mục đích đó. Xem thêm: Why do constructors not return values?

3

Bởi vì các nhà xây dựng trừu tượng không được hỗ trợ.

Nhưng lớp trừu tượng có thể có hàm tạo.

3

gì sai với điều này:

public abstract class MyClass { 
    protected MyClass(int param) 
    { 
    } 
} 

Trong trường hợp này, bạn bắt buộc tất cả các lớp thừa kế để gọi constructor lớp cơ sở.

+1

Nó buộc lớp phải khai báo một hàm tạo, nhưng không nhất thiết phải là một lớp có tham số nguyên. Bạn có thể dễ dàng khai báo nó là 'public class NewClass: MyClass {public NewClass(): base (0) {}}' – tvanfosson

+0

Bạn có thể sử dụng xác nhận đối số trong hàm tạo MyClass và ném ngoại lệ do đối số không hợp lệ. Nhưng bạn không thể ép buộc các lớp dẫn xuất để truyền dữ liệu hợp lệ cho hàm tạo MyClass và không thêm các hàm tạo bổ sung trong các lớp dẫn xuất. –

+1

Làm rõ nhỏ - họ không * có nghĩa vụ * gọi nó, nhưng họ * có thể * gọi nó. – slugster

6

Tóm tắt ngụ ý ảo. Một constructor không mặc định không bao giờ có thể được gọi là đa hình, vì vậy ảo và trừu tượng không được phép trên các hàm tạo. NẾU trong phiên bản tương lai của C#, generics được tăng cường để cho phép gọi các constructor không mặc định thông qua một tham số kiểu generic, sau đó các cuộc gọi đa hình tới các nhà xây dựng sẽ có thể và các nhà xây dựng ảo và trừu tượng có thể được thêm vào.

+2

Gọi một hàm tạo không mặc định trong một phương thức chung là vẫn không phải là một cuộc gọi đa hình, vì kiểu này được biết trước. Một nhà xây dựng không bao giờ có thể được gọi là đa hình, thời gian. –

+0

@AntonTykhyy: Các cuộc gọi trong ngữ cảnh chung * là * đa hình. NET Generics làm việc dựa trên loại xóa và công văn ảo. Chúng không chuyên biệt cho mỗi kiểu theo cách mà các mẫu C++. –

+0

Đó là nếu bạn bỏ qua các loại giá trị. Generics đóng trên các loại giá trị _are_ chuyên ngành. Chỉ cần tưởng tượng như thế nào khủng khiếp 'Danh sách ' vv sẽ được nếu không. Nhưng tôi hiểu ý anh là gì. Tôi cho rằng người ta có thể thêm một slot trong 'RuntimeTypeHandle' cho mỗi constructor được sử dụng trong một ràng buộc chung. Nhưng nếu sau này ai đó tải một assembly có một ràng buộc constructor chung mới thì sao? Tất cả 'RuntimeTypeHandle' hiện có sẽ phải được cập nhật. Không nói rằng nó không thể được thực hiện, chỉ cần rất nhiều rắc rối. –

5

Các nhà xây dựng gần với phương pháp tĩnh hơn là các phương pháp "thông thường". Giống như phương pháp tĩnh, chúng có thể bị quá tải, nhưng không được ghi đè số. Đó là, họ không được thừa kế nhưng có thể được định nghĩa lại.

public BaseClass 
{ 
    public BaseClass(String s) { ... } 
    public static void doIt (String s) { ... } 
} 

public SubClass extends BaseClass 
{ 
    public SubClass(String s) { ... } 
    public static void doIt (String s) { ... } 
} 

public SubClass2 extends BaseClass 
{ 
} 

new SubClass("hello"); 
SubClass.doIt("hello"); 

new SubClass2("hello"); // NOK 
SubClass2.doIt("hello"); // NOK 

nhà xây dựng và phương pháp tĩnh là không bao giờ cử động (hầu như) - Bạn luôn biết loại bê tông bạn nhanh chóng hoặc lớp bê tông của phương pháp tĩnh.Đó là lý do tại sao nó không có ý nghĩa để có một hàm dựng trừu tượng trừu tượngphương thức tĩnh trừu tượng. Đó là lý do tại sao bạn cũng không thể chỉ định hàm tạo và phương thức tĩnh trong các giao diện .

Bạn thậm chí có thể nghĩ đến constructor như tĩnh phương pháp nhà máy (và xem corresponding pattern):

MyClass obj = new MyClass(); // the way it is 
    MyClass obj = MyClass.new(); // think of it like this 

Trường hợp duy nhất tôi nhìn thấy nơi nó sẽ làm cho tinh thần để xác định constructor trừu tượng hoặc phương pháp tĩnh trừu tượng sẽ nếu phản ánh được sử dụng. Trong trường hợp này, bạn có thể đảm bảo rằng tất cả các lớp con sẽ xác định lại phương thức tĩnh tương ứng hoặc hàm tạo. Nhưng phản ánh là một chủ đề khác ...

Lưu ý: bằng các ngôn ngữ như Smalltalk, nơi các lớp là đối tượng thông thường, bạn có thể ghi đè phương pháp tĩnh và có hàm tạo trừu tượng. Nhưng nó không áp dụng cho Java vì các lớp không phải là các đối tượng "thông thường" ngay cả khi bạn có thể nhận được chúng với sự phản chiếu.

+0

+1 cho trường hợp sử dụng phản chiếu. – fre0n