2010-09-19 63 views
41

Tôi có một lớp cơ sở và một cơ sở kế thừa lớp. Lớp cơ sở có một số hàm ảo mà lớp thừa hưởng có thể ghi đè lên. Tuy nhiên, các hàm ảo trong lớp cơ sở có mã phải chạy trước khi ghi đè lớp thừa hưởng được gọi. Có một số cách mà tôi có thể gọi các lớp cơ sở chức năng ảo đầu tiên sau đó thừa kế lớp thừa kế. Không cần gọi hàm base.function().Chức năng cơ sở cuộc gọi sau đó được thừa kế chức năng

Tôi biết tôi chỉ đơn giản có thể tạo hai hàm, một hàm được gọi, hàm ảo khác. Nhưng có cách nào tôi có thể giữ cùng tên không? Tôi biết tôi có thể cần phải thay đổi một số thứ xung quanh.

class myBase 
{ 
    public virtual myFunction() 
     { /* must-run code, Called first */ } 
} 

class myInherited : myBase 
{ 
    public override myFunction() 
     { /* don't use base.myFunction();, 
     called from base.myFunction(); */ } 
} 

Câu hỏi tương tự here.

Trả lời

44

Một giải pháp phổ biến có thể tìm thấy trong Khuôn khổ .NET là tách phương thức theo phương thức công khai XXX và phương pháp ảo được bảo vệ OnXXX được gọi theo phương pháp công khai. Ví dụ của bạn, nó sẽ trông như thế này:

class MyBase 
{ 
    public void MyMethod() 
    { 
     // do something 
     OnMyMethod(); 
     // do something 
    } 

    protected virtual void OnMyMethod() 
    { 
    } 
} 

class MyInherited : MyBase 
{ 
    protected override void OnMyMethod() 
    { 
     // do something 
    } 
} 
+0

Có cách nào tôi có thể thực hiện việc này mà không cần thực hiện hai chức năng trong lớp cơ sở không?hoặc ít nhất làm cho họ có cùng tên? – Dave

+3

@Dave: Không, không có cách nào để gọi một phương thức cơ bản được ghi đè trước hoặc sau cuộc gọi phương thức ảo một cách kỳ diệu. Bạn phải chia nó theo một cách nào đó. (Nếu bạn chia nhỏ nó, bạn cũng có thể thực thi một phương thức ghi đè gọi phương thức cơ sở được ghi đè, ngoài việc làm điều gì đó trước và sau phương thức được bảo vệ.) – dtb

+3

Điều này còn được gọi là thành ngữ Giao diện Phi-ảo - http: // vi. wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface – sll

60

C# không có hỗ trợ cho tự động thực thi điều này, nhưng bạn có thể thực thi nó bằng cách sử dụng các template method pattern. Ví dụ, hãy tưởng tượng bạn có mã này:

abstract class Animal 
{ 
    public virtual void Speak() 
    { 
     Console.WriteLine("I'm an animal."); 
    } 
} 

class Dog : Animal 
{ 
    public override void Speak() 
    { 
     base.Speak(); 
     Console.WriteLine("I'm a dog."); 
    } 
} 

Vấn đề ở đây là bất kỳ lớp kế thừa từ Animal nhu cầu gọi base.Speak(); để đảm bảo hoạt động cơ sở được thực thi. Bạn có thể tự động thực thi điều này bằng cách dùng phương pháp sau (hơi khác nhau):

abstract class Animal 
{ 
    public void Speak() 
    { 
     Console.WriteLine("I'm an animal."); 
     DoSpeak(); 
    } 

    protected abstract void DoSpeak(); 
} 

class Dog : Animal 
{ 
    protected override void DoSpeak() 
    { 
     Console.WriteLine("I'm a dog."); 
    } 
} 

Trong trường hợp này, khách hàng vẫn chỉ thấy đa hình Speak phương pháp, nhưng hành vi Animal.Speak được đảm bảo để thực thi. Vấn đề là nếu bạn có thừa kế hơn nữa (ví dụ: class Dachshund : Dog), bạn phải tạo một phương thức trừu tượng khác nếu bạn muốn Dog.Speak được đảm bảo thực thi.

0

Không có cách nào để thực hiện những gì bạn đang tìm kiếm ngoài 2 cách bạn đã đặt tên.

Hoặc bạn tạo 2 hàm trong lớp cơ sở, một hàm được gọi và hàm ảo khác.

Hoặc bạn gọi base.functionName trong lớp phụ.

0

Không chính xác. Nhưng tôi đã làm một cái gì đó tương tự bằng cách sử dụng phương pháp trừu tượng.

Phương pháp trừu tượng phải được ghi đè bởi các lớp dẫn xuất. Tóm tắt procs là ảo, do đó bạn có thể chắc chắn rằng khi lớp cơ sở gọi chúng là phiên bản của lớp dẫn xuất được gọi. Sau đó, có "Must Run Code" của lớp cơ sở của bạn gọi proc trừu tượng sau khi chạy. Tuy nhiên, mã lớp cơ sở của bạn luôn luôn chạy đầu tiên (đảm bảo rằng lớp cơ sở proc không còn là ảo nữa) theo sau là mã của lớp dẫn xuất của bạn.

class myBase 
{ 
    public /* virtual */ myFunction() // remove virtual as we always want base class's function called here 
    { /* must-run code, Called first */ 

     // call derived object's code 
     myDerivedMustcallFunction();  
    } 

    public abstract myDerivedMustCallFunction() { /* abstract functions are blank */ } 
} 

class myInherited : myBase 
{ 
    public override myDerivedMustCallFunction() 
    { /* code to be run in derived class here */ } 
} 
+1

Tại sao phương thức trừu tượng lại công khai? – Casey

0

Bạn nghĩ gì về điều này?

class myBase 
{ 
    public void myFunctionWrapper() 
    { 
     // do stuff that must happen first 
     // then call overridden function 
     this.myFunction(); 
    } 

    public virtual void myFunction(){ 
     // default implementation that can be overriden 

    } 

} 

class myInherited : myBase 
{ 
    public override void myFunction() 
    { 

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