2010-10-20 48 views
18

Có cấu trúc nào trong Java hoặc C# có buộc phải kế thừa các lớp để gọi triển khai cơ sở không? Bạn có thể gọi super() hoặc base() nhưng nó có thể có nó ném một lỗi biên dịch thời gian nếu nó không được gọi? Điều đó sẽ rất thuận tiện ..Phương thức cơ sở về lực gọi

--edit--

Tôi chủ yếu tò mò về phương pháp ghi đè.

+0

Bạn có nghĩa là từ một constructor khi trọng phương pháp? – munificent

Trả lời

12

Không có và không nên làm bất cứ điều gì.

Điều gần nhất tôi có thể nghĩ đến tay ra nếu một cái gì đó giống như có này trong lớp cơ sở:

public virtual void BeforeFoo(){} 

public void Foo() 
{ 

this.BeforeFoo(); 
//do some stuff 
this.AfterFoo(); 

} 

public virtual void AfterFoo(){} 

Và cho phép các lớp kế thừa override BeforeFoo và/hoặc AfterFoo

+5

Những gì bạn đề xuất có vẻ là giải pháp phổ biến của vấn đề. Mặc dù có sức mạnh (hoặc tự động gọi nó) lớp kế thừa để gọi nó sẽ thuận tiện và sẽ làm cho một số lỗi dễ tìm thấy. Bạn có thể giải thích lý do tại sao có * không nên * là bất kỳ tính năng nào không? Liệu nó có đi ngược lại các khái niệm đa hình cơ bản và nếu nó có, tại sao? – irwinb

+0

Nếu tôi có một lớp học mở rộng một lớp học khác mà buộc tôi phải gọi base.Foo() ở đâu đó trong Foo của tôi, điều đó khá hạn chế. Tôi hoặc gọi base.Foo() nếu tôi muốn chức năng đó, hoặc tôi không thể sử dụng lớp để mở rộng của tôi. Trình biên dịch nên thực thi một bộ quy tắc cơ bản tối thiểu. Bạn nên kiểm tra các hợp đồng mã cho .NET http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx – MStodd

0

Đừng nghĩ rằng có bất kỳ giải pháp khả thi nào được tích hợp sẵn. Tôi chắc rằng có các công cụ phân tích mã riêng biệt có thể thực hiện điều đó.

0

EDIT Xây dựng sai lầm làm hàm tạo. Rời khỏi CW vì nó phù hợp với một tập con rất hạn chế của vấn đề.

Trong C#, bạn có thể ép buộc hành vi này bằng cách xác định một hàm tạo duy nhất có ít nhất một tham số trong kiểu cơ sở. Điều này loại bỏ hàm khởi tạo mặc định và bắt buộc các kiểu dẫn xuất để giải mã cơ sở được chỉ định hoặc chúng nhận được một lỗi biên dịch.

class Parent { 
    protected Parent(int id) { 
    } 
} 

class Child : Parent { 
    // Does not compile 
    public Child() {} 
    // Also does not compile 
    public Child(int id) { } 
    // Compiles 
    public Child() :base(42) {} 

} 
+0

Tôi tin rằng điều này cũng hoạt động trong Java. – BoltClock

+0

Tôi nghĩ rằng OP đang nói về việc có thể bắt buộc 'public override void Method() {base.Method(); ...} ', không phải về các nhà xây dựng. – Ani

+0

Điều này chỉ làm việc cho các nhà xây dựng, mặc dù. –

6

Không có trong Java. Nó có thể là có thể trong C#, nhưng người khác sẽ phải nói chuyện với điều đó.

Nếu tôi hiểu đúng bạn muốn điều này:

class A { 
    public void foo() { 
     // Do superclass stuff 
    } 
} 

class B extends A { 
    public void foo() { 
     super.foo(); 
     // Do subclass stuff 
    } 
} 

Những gì bạn có thể làm trong Java để thực thi việc sử dụng của foo lớp cha là một cái gì đó như:

class A { 
    public final void foo() { 
     // Do stuff 
     ... 
     // Then delegate to subclass 
     fooImpl(); 
    } 

    protected abstract void fooImpl(); 
} 

class B extends A { 
    protected void fooImpl() { 
     // Do subclass stuff 
    } 
} 

Nó xấu xí, nhưng nó đạt được những gì bạn muốn. Nếu không, bạn sẽ phải cẩn thận để đảm bảo rằng bạn gọi phương thức superclass.

Có thể bạn có thể tinker với thiết kế của mình để khắc phục sự cố, thay vì sử dụng giải pháp kỹ thuật. Nó có thể là không thể nhưng có lẽ là giá trị suy nghĩ về.

EDIT: Có thể tôi đã hiểu nhầm câu hỏi. Bạn đang nói về chỉ các nhà xây dựng hoặc các phương pháp nói chung? Tôi giả định các phương pháp nói chung.

+1

+1: Tôi không nghĩ nó xấu xí. Đó là mẫu phương thức mẫu và phương pháp thích hợp. Tên fooImpl() là xấu xí, nhưng đây chỉ là một ví dụ ... –

0

Trong java, trình biên dịch chỉ có thể thực thi điều này trong trường hợp của Constructors.

Một hàm tạo phải được gọi là tất cả các đường lên chuỗi thừa kế .. tức là nếu Dog mở rộng Animal extends Thing, hàm tạo cho Dog phải gọi một hàm tạo cho Animal phải gọi một hàm tạo cho Thing.

Đây không phải là trường hợp cho các phương pháp thông thường, nơi lập trình viên phải gọi một cách rõ ràng việc triển khai siêu nếu cần.

Cách duy nhất để thực thi một số mã thực hiện căn cứ để được chạy là để chia đang override-thể thành một phương pháp gọi riêng biệt:

public class Super 
{ 
    public final void doIt() 
    { 
    // cannot be overridden 
     doItSub(); 
    } 

    protected void doItSub() 
    { 
    // override this 
    } 
} 

public class Sub extends Super 
{ 
    protected void doItSub() 
    { 
    // override logic 
    } 
} 
2

Nếu tôi hiểu đúng bạn muốn thực thi rằng hành vi của lớp cơ sở của bạn là không overriden, nhưng vẫn có thể mở rộng nó, sau đó tôi sẽ sử dụng mẫu thiết kế phương thức mẫu và trong C# không bao gồm từ khóa ảo trong định nghĩa phương thức.

1

Không. Không thể thực hiện được. Nếu bạn cần phải có một chức năng mà một số trước hoặc sau hành động làm điều gì đó như thế này:

internal class Class1 
{ 
    internal virtual void SomeFunc() 
    { 
     // no guarantee this code will run 
    } 


    internal void MakeSureICanDoSomething() 
    { 
     // do pre stuff I have to do 

     ThisCodeMayNotRun(); 

     // do post stuff I have to do 
    } 

    internal virtual void ThisCodeMayNotRun() 
    { 
     // this code may or may not run depending on 
     // the derived class 
    } 
} 
0

Tôi vấp vào bài đăng này và không nhất thiết phải thích bất kỳ câu trả lời cụ thể nào, vì vậy tôi nghĩ mình sẽ cung cấp câu trả lời cho riêng mình ...

Không có cách nào trong C# để thực thi phương thức cơ bản được gọi. Vì vậy, mã hóa như vậy được coi là một mô hình chống từ khi một nhà phát triển tiếp theo có thể không nhận ra họ phải gọi phương thức cơ sở khác lớp sẽ ở trạng thái không đầy đủ hoặc xấu.

Tuy nhiên, tôi đã tìm thấy các trường hợp mà loại chức năng này là bắt buộc và có thể được đáp ứng cho phù hợp. Thông thường lớp dẫn xuất cần một tài nguyên của lớp cơ sở. Để có được tài nguyên, thông thường có thể được hiển thị thông qua một thuộc tính, nó được thay thế bằng phương thức. Lớp dẫn xuất không có sự lựa chọn nào khác ngoài việc gọi phương thức để lấy tài nguyên, do đó đảm bảo rằng phương thức lớp cơ sở được thi hành.

Câu hỏi logic tiếp theo mà người ta có thể hỏi là tại sao không đặt nó vào hàm tạo? Lý do là nó có thể là một thứ tự của vấn đề hoạt động. Vào thời điểm lớp học được xây dựng, có thể có một số yếu tố đầu vào vẫn còn thiếu.

Điều này có thoát khỏi câu hỏi không? Có và không. Có, nó ép buộc lớp dẫn xuất gọi một phương thức lớp cơ sở cụ thể. Không, nó không làm điều này với từ khóa ghi đè. Điều này có thể hữu ích cho một cá nhân đang tìm kiếm câu trả lời cho bài đăng này, có thể.

Tôi không rao giảng điều này như phúc âm, và nếu cá nhân thấy một nhược điểm của phương pháp này, tôi rất thích nghe về nó.

1

Tôi không đọc TẤT CẢ các câu trả lời ở đây; tuy nhiên, tôi đã xem xét cùng một câu hỏi. Sau khi xem xét những gì tôi thực sự muốn làm, có vẻ như với tôi rằng nếu tôi muốn FORCE cuộc gọi đến phương thức cơ bản mà tôi không nên khai báo phương thức cơ sở ảo (ghi đè) có thể ở vị trí đầu tiên.

2

Ví dụ sau ném một số InvalidOperationException khi chức năng cơ sở không được kế thừa khi ghi đè phương thức.

Điều này có thể hữu ích cho các tình huống trong đó phương thức được gọi bởi một số API nội bộ.

tức lànơi Foo() không được thiết kế để gọi trực tiếp:

public abstract class ExampleBase { 
    private bool _baseInvoked; 

    internal protected virtual void Foo() { 
     _baseInvoked = true; 
     // IMPORTANT: This must always be executed! 
    } 

    internal void InvokeFoo() { 
     Foo(); 
     if (!_baseInvoked) 
      throw new InvalidOperationException("Custom classes must invoke `base.Foo()` when method is overridden."); 
    } 
} 

trình:

public class ExampleA : ExampleBase { 
    protected override void Foo() { 
     base.Foo(); 
    } 
} 

hét lên:

public class ExampleB : ExampleBase { 
    protected override void Foo() { 
    } 
} 
Các vấn đề liên quan