Sự khác biệt giữa phương thức ảo và phương thức trừu tượng

Cái này liên quan tới khái niệm đa hình (polymorphism, giống kiểu transformer robốt biến hình ý) trong OOP. Nếu bạn từ java sang thì có thể hơi khó hiểu vì Java nó implement mặc định (C++ và C# thì phân biệt cái này rõ ràng hơn)

class Human {
   public void pee() {Console.WriteLine("Pee pee ..."); }
}

class Man : Human {
   public void pee() {Console.WriteLine("Stand pee ...");}
   public void  shit() {Console.WriteLine("Sit shit ..."); }
}

Giờ bạn gọi thế này

Human b = new Human(); b.pee(); //output: Pea pea ..., giả sử là em bé đi tè nhé
Man m = new Man(); m.pee(); //output: Stand pee ...
Human k = new Man(); k.shit(); //fail mặc dù k là Man, nhưng hiện đang trong hình dáng là Human, mà Human chưa có function này 

OK, vì b và m đều hiện giờ có hình dáng (form) là Human và Man tương ứng nên compiler nó hiểu và gọi đúng override function. Còn k dù là Man, nhưng vì đang ở hình dáng Human nên k biết đi i … (kiểu thiểu năng ý, có thể nằm và … ^^)

Tuy nhiên nếu giờ có một function thế này trong Human

void Foo(Human h){ h.pee();}

Nếu giờ gọi:

Human a = new Human(); a.Foo(); //output: Pee pee ...
Man n = new Man(); n.Foo(); //output: Pee pee ...

Tuy có hình dáng là Man, nhưng khi truyền vào Foo() lại chuyển sang hình dáng là Human, vậy nên nó sẽ gọi cái nào? Theo như output thì nó sẽ gọi cái pee của Human. Giờ muốn nó gọi cái pee của Man thì phải làm sao -> giải pháp, khai báo cái pee() trong Human là virtual (hàm ảo, vì thực ra hàm này sẽ k được gọi dù hình dáng là Human bởi sang các class con, đã có hàm này riêng rồi)

Trong java, không cần khai báo virtual, nó cũng gọi override function.