让我们来比较C#,C++和Java之间重写虚函数的区别
這篇文章比較了C++,C#和Java在面向對象中的繼承和函數重寫的不同。
介紹
我一直用三種不同的面向對象的語言,這三種語言都很明顯的支持繼承和遲綁定或者虛函數。我認為一篇好的文章當我在用Java,c#和C++中切換時他們在語法和內定行為的不同地方會提醒我。
背景
我不斷的在切換用C++寫霜凍視頻游戲引擎和用C#寫工具和網頁服務器。我也用Java寫我的安卓主要的項目(最新的一個是群集智能的螞蟻巢穴模擬器-敬請期待)
同樣我認為我要給自己做筆記,在繼承、函數重寫(虛函數)使用三種不同的語言直接的主要區別。
使用代碼
可接入性
C++支持共有,保護,和私有繼承。但是無論它做了什么,不要忘了任何的私有成員總是私有的,不能變為可接入的為任何基礎或派生類調用。
?
Java簡化了繼承并且只允許共有繼承。
?
C#在這個方面仿照了Java。
?
大家都普遍同意在面向對象語言中通過封裝和其他功能可實現保護和私有繼承,不需要這些其他復制的置換。
多繼承
現在我們來將一點關于多繼承。當建立了一個類的層級時,C++只用冒號繼承,緊隨其后的是逗號,用來分開其他基類列表。C++是唯一一個支持多繼承的語言,如果你一不小心那將會出現像致命的死亡菱形(DDD)結構這種事情。總體來說,命的死亡菱形(DDD)是一個設計,這個設計是多個同一類是對象的一部分實例。設想一個類叫Dog,這個Dog繼承了Animal和Pet,并且這個Animal和Pet都繼承了一個叫Printable的類,狗這個實例現在有兩個叫Printable的基類的實例。當你在Dog這個類里面改變了這個Printable類的屬性后會發生什么呢?它是否會改變實例1或實例2的屬性呢?等等等。為了避免繼承里面這種復雜的問題(無論如何,我們通常喜歡類的組合勝過繼承-組合展開是一個原因),C#和Java兩者都不支持多繼承。
接口
多年前,C++還是這個編程大陸的王者時,你可能會用抽象類(一個不能被實例化的類,而且最少包含了一個純虛函數)并且要把所有的純虛函數定義為一種格式也就是=0。這就意味著你需要在派生類中實現這些功能。這樣就誕生了接口這個定義。在C#和Java中你能操作接口,從而給你類似與多繼承的一種協定(或者你必須執行函數簽名)
?
C#不僅支持接口(類似與C++里面的抽象類,類中包含了索引的純虛函數)還支持帶有一個或多個存虛函數的抽象類,并且這些函數是帶有某種真實的功能。記住接口和抽象類里的函數必須是公用,這樣就可以在調用類的時候對他們進行直接訪問,在接口里面定義私有函數往往沒有太多意義,誰又能調用它呢?抽象類中這個類是不能調用他自己的函數,這是沒有意義的!所以,C#涵蓋了抽象類、接口和具體類這三種。
?
讓我們來看這些用三種編程語言,帶有繼承和接口聲明類的代碼。
C++
class derived : public base, base2 //C++ class definition with 2 public inherited classes
Java
class Derived extends Base implements printable // new derived class that derives from base, and implements the printable contractC# public interface printable //A contract interface public abstract class baser //A class with one or more abstact functions public class derived : baser, printable //A derived class from baser, it implements the printable interface
虛函數
面向對象的另一個方面是多態。這種方法是一種是在運行是構建的,在編譯類型時我們只知道它的層次結構,舉一個繼承中衍生類的例子,我們有一個基類型的指針。使用遲綁定調用這個函數,這個函數是在運行中被判斷而不是編譯時。這三種語言都支持遲綁定這就是虛函數。
C++
有一個老舊的思想是默認把這個函數設置為非純虛函數。正如待會我說的那樣,如果你有一個基類和一個派生類,他們倆都有一個叫print()的函數,你實構建哪種類的實例都沒有關系,你將在類上調用函數這取決你引用或者指針是什么類型,如果你不知道你指向的是什么。用虛函數,你一定要聲明虛函數(這種層次結構在哪都是非常好的),這是告訴編譯器創建一個虛函數表,當運行是你要查找函數的地址就會依賴這張表里面。一旦函數被標記成虛函數,實例將會判決到哪調用你的函數,不再依賴于引用和指針。
Java
Java一項都超級簡單,所有的函數都是虛函數,不需要任何陳述去告訴運行引擎那些是虛函數,如果一個派生類和基類都聲明了一個叫print的函數,都具有同樣的簽名,那么實例將依賴JRE的決定。超級簡單!除非你不想要這個功能(也許安全是個令人擔憂的問題比如你不想函數void?AddMoneyToBankAccount()被重寫),在這種情況下你要標記它為常函數,并且不要想著去重寫它!艸!
C#
最后是C#,在C#這里所有函數默認都是非虛函數,不僅僅是這樣,如果你想去重寫一個函數,你得這個在基類上打上虛函數這個標簽,并且重新時也要打上這個前綴標簽。你可以做到的,然而,有兩個相同簽名的函數,在繼承關系里面,并且他們并不是被重寫的關系,你要給派生類的那個函數打上“new”?這個標簽。你要明確的告訴編譯器,我是故意這么做的。你想隱藏基類函數的功能,并且這不是虛函數。但是如果你調用函數用的是基類的指針,它將總是調用基類的函數,即使你指向一個派生類的指針,你所看的這樣的功能是編譯器靜態鏈接時做的,運行時是動態的(盡管沒有專門的C#編譯器)
?
最后一些代碼來說明所有的虛函數和函數重寫!!
C++ Code
#include "stdafx.h" #include <iostream>using namespace std;class base {public:void hello(){cout << "Base func non-virtual" << endl;}virtual void hello2(){cout <<"Base func virtual"<<endl;} };class derived : public base //C++ class definition with 2 inherited classes { public:void hello(){cout << "Derived func non-virtual" << endl;}virtual void hello2(){cout <<"Derived func virtual"<<endl;}};int main() {cout << "calling function defined in both base and der that is NOT virtual, then calling a function that is virtual" << endl;{cout << "Instance is Derived - Reference is Derived" << endl;derived d;d.hello();d.hello2();}{cout << "Instance is Derived - Reference is Base" << endl;base *f = new derived ;f->hello();f->hello2();}{cout << "Instance is Base - Reference is Base" << endl;base t;t.hello();t.hello2();}{cout << "Instance is Derived - reinterpret cast to base - Reference is Derived" << endl;derived *g = new derived ;base *j = reinterpret_cast<base*>(g);j->hello();j->hello2();}getchar();return 0; } And the output:calling function defined in both base and der that is NOT virtual, then calling a function that is virtual Instance is Derived - Reference is Derived Derived func non-virtual Derived func virtual Instance is Derived - Reference is Base Base func non-virtual Derived func virtual Instance is Base - Reference is Base Base func non-virtual Base func virtual Instance is Derived - reinterpret cast to base - Reference is Derived Base func non-virtual Derived func virtual
And C#
using System;namespace ConsoleApplication2 {public class based{public void hello(){Console.WriteLine("hello on base instance - non virtual on base");Console.WriteLine("func is - non virtual on deriv");}public virtual void hello2(){Console.WriteLine("hello2 on base instance - virtual on base");Console.WriteLine("func is - virtual on deriv");}public void hello3(){Console.WriteLine("hello3 on base instance - non virtual on base");Console.WriteLine("func is new and virtual on deriv");}public virtual void hello4(){Console.WriteLine("hello4 on base instance - virtual on base");Console.WriteLine("func is new and virtual on deriv");}public virtual void hello5(){Console.WriteLine("hello5 on base instance - virtual on base");Console.WriteLine("func is override on deriv");}public void hello6(){Console.WriteLine("hello6 on base instance - NOT virtual on base");Console.WriteLine("func is override on deriv");}}public class derived : based {public void hello(){Console.WriteLine("hello on deriv - non virtual on deriv");Console.WriteLine("func is non virtual on base");}public virtual void hello2(){Console.WriteLine("hello2 on deriv - virtual on deriv");Console.WriteLine("func is virtual on base");}public new virtual void hello3(){Console.WriteLine("hello3 on deriv - new and virtual on deriv");Console.WriteLine("func is non virtual on base");}public new virtual void hello4(){Console.WriteLine("hello4 on deriv - new and virtual on deriv");Console.WriteLine("func is virtual on base");}public override void hello5(){Console.WriteLine("hello5 on deriv - override on deriv");Console.WriteLine("func is virtual on base");}}class Program{static void Main(string[] args){Console.WriteLine("base ref with base inst");based b = new based();b.hello();b.hello2();b.hello3();b.hello4();b.hello5();Console.WriteLine();Console.WriteLine("deriv ref with deriv inst");derived d = new derived();d.hello();d.hello2();d.hello3();d.hello4();d.hello5();Console.WriteLine();Console.WriteLine("base ref with deriv inst");based o = new derived();o.hello();o.hello2();o.hello3();o.hello4();o.hello5();Console.WriteLine();Console.WriteLine("deriv ref with deriv inst cast back to base ref");derived s = new derived();based ds = s;ds.hello();ds.hello2();ds.hello3();ds.hello4();ds.hello5();Console.WriteLine("The end--");Console.ReadLine();}} }And the output:
base ref with base inst hello on base instance - non virtual on base func is - non virtual on deriv hello2 on base instance - virtual on base func is - virtual on deriv hello3 on base instance - non virtual on base func is new and virtual on deriv hello4 on base instance - virtual on base func is new and virtual on deriv hello5 on base instance - virtual on base func is override on derivderiv ref with deriv inst hello on deriv - non virtual on deriv func is non virtual on base hello2 on deriv - virtual on deriv func is virtual on base hello3 on deriv - new and virtual on deriv func is non virtual on base hello4 on deriv - new and virtual on deriv func is virtual on base hello5 on deriv - override on deriv func is virtual on basebase ref with deriv inst hello on base instance - non virtual on base func is - non virtual on deriv hello2 on base instance - virtual on base func is - virtual on deriv hello3 on base instance - non virtual on base func is new and virtual on deriv hello4 on base instance - virtual on base func is new and virtual on deriv hello5 on deriv - override on deriv func is virtual on basederiv ref with deriv inst cast back to base ref hello on base instance - non virtual on base func is - non virtual on deriv hello2 on base instance - virtual on base func is - virtual on deriv hello3 on base instance - non virtual on base func is new and virtual on deriv hello4 on base instance - virtual on base func is new and virtual on deriv hello5 on deriv - override on deriv func is virtual on base The end--
And lastly Java
package com.roboticsfordreamers;class Base implements {public void Hello(){System.out.println("Hello this the base");} }class Derived extends Base {public void Hello(){System.out.println("Hello this the derived");} }public class Main {public static void main(String[] args) {Base b = new Base();Derived d = new Derived();Base b2 = new Derived();b.Hello();d.Hello();b2.Hello();} } And the output:Hello this the base Hello this the derived Hello this the derivedProcess finished with exit code 0
我希望你能找到對你有用知識。
原文:https://www.codeproject.com/Tips/1164135/Overriding-Virtual-Functions-a-Comparison-Between
PS:這篇有點難,部分地方翻譯不到位
總結
以上是生活随笔為你收集整理的让我们来比较C#,C++和Java之间重写虚函数的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++无限关机(提权例子)
- 下一篇: mysql怎么更改属性_MySQL 中怎