2013-08-12 42 views
5

Tôi đang cố gắng hiểu cách thức hoạt động của kế thừa trong C#. Tôi đã viết đoạn mã sau:Về thừa kế C#

class Program 
{ 
    static void Main(string[] args) 
    { 
     Animal animal = new Dog(); 
     animal.OverRideMe(); 
     //animal.NewMethod(); 
     Dog dog = (Dog)animal; 
     dog.OverRideMe(); 
     dog.NewMethod(); 
     Console.Read(); 
    } 
} 
public abstract class Animal 
{ 
    public Animal() 
    { 
     Console.WriteLine("Base Constructor"); 
    } 
    public virtual void OverRideMe() 
    { 
     Console.WriteLine("In Base Class's OverRideMe"); 
     Console.Read(); 
    } 
} 
public class Dog : Animal 
{ 
    public Dog() 
    { 
     Console.WriteLine("Derived Constructor"); 
    } 
    public override void OverRideMe() 
    { 
     Console.WriteLine("In Derived Class's OverRideMe"); 
     Console.Read(); 
    } 
    public void NewMethod() 
    { 
     Console.WriteLine("In Derived Class's NewMethod"); 
     Console.Read(); 
    } 
} 

Các CIL (Common Intermediate Language) mã cho Main() trông giống như sau:

.method private hidebysig static 
    void Main (
     string[] args 
    ) cil managed 
{ 
    // Method begins at RVA 0x2050 
    // Code size 42 (0x2a) 
    .maxstack 1 
    .entrypoint 
    .locals init (
     [0] class ConsoleApplication1.Animal animal, 
     [1] class ConsoleApplication1.Dog dog 
    ) 

    IL_0000: nop 
    IL_0001: newobj instance void ConsoleApplication1.Dog::.ctor() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: callvirt instance void ConsoleApplication1.Animal::OverRideMe() 
    IL_000d: nop 
    IL_000e: ldloc.0 
    IL_000f: castclass ConsoleApplication1.Dog 
    IL_0014: stloc.1 
    IL_0015: ldloc.1 
    IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe() 
    IL_001b: nop 
    IL_001c: ldloc.1 
    IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod() 
    IL_0022: nop 
    IL_0023: call int32 [mscorlib]System.Console::Read() 
    IL_0028: pop 
    IL_0029: ret 
} // end of method Program::Main 

Các dòng trong CIL được gây phiền hà cho tôi là:

IL_000f: castclass ConsoleApplication1.Dog 
IL_0014: stloc.1 
IL_0015: ldloc.1 
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe() 
IL_001b: nop 
IL_001c: ldloc.1 
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod() 

Sau castclass của động vật để Chó nhập mã thực thi dog.OverRideMe();. Đây được phiên dịch sang CIL như

IL_0016: callvirt dụ trống ConsoleApplication1.Animal :: OverRideMe()

tôi đã đúc các động vật đối tượng để Chó loại. Tại sao nên dog.OverRideMe(); được dịch sang câu lệnh trên trong CIL? Sản lượng của các mã trên là:

enter image description here

sản lượng này không có gì để làm với cơ sở lớp Animal nhưng CIL vẫn đặt một cuộc gọi đến nó.

+2

Tôi không hiểu nhu cầu giảm bớt câu hỏi này. Ít nhất để lại một bình luận để tôi có thể cải thiện nó. – msiyer

+1

Câu hỏi của bạn là tốt, và thẳng thắn là một câu hỏi hay. Bỏ qua những kẻ thù ghét, họ không thể kiểm soát trên trang web những ngày này IMO. – jason

Trả lời

4

Bạn đang gọi một phương thức ảo. Lời gọi phương thức ảo được xác định theo loại đối tượng thời gian chạy. Bạn có thể gọi nó là Dog tất cả những gì bạn muốn, nhưng trình biên dịch vẫn sẽ phát ra hướng dẫn để xác định phương thức thích hợp để gọi tại thời gian chạy . Bắt đầu với thời gian biên dịch loại dog, nó đi lên chuỗi thừa kế cho đến khi tìm thấy định nghĩa "cấp cao nhất" của OverRideMe và phát ra lời gọi phương thức ảo cho điều đó. Trong trường hợp này, vị trí cao nhất trong chuỗi thừa kế OverRideMe được xác định là trong Animal; do đó, nó phát ra lời gọi phương thức ảo cho Animal.OverRideMe.

Dưới đây là một số previous answer có thể giúp bạn hiểu những gì đang diễn ra tốt hơn một chút.

: Vị trí cao nhất trong chuỗi kế thừa nơi phương thức được xác định. Một số dịch vụ chăm sóc phải được thực hiện ở đây để hiểu cách thức ẩn phương pháp và những gì không ảnh hưởng đến điều này.

+0

Bạn có thể cần xem từ khóa mới trong chữ ký phương thức. Điều này sẽ gọi phương thức trên loại thực tế không phải là ghi đè. – Sebi

+1

@Sebi: Có * không * từ khoá 'mới' được sử dụng để ẩn bất kỳ phương thức nào trong mã của OP. – jason

0

Nó nói "callvirt" - bảng ảo được liên kết với lớp "Động vật" nên đó là nơi đặt cuộc gọi. Sau khi giải quyết bảng ảo, trong thời gian chạy, phương thức dự định sẽ được gọi.