C++的類與C#的類[zt]
2024-07-21 02:22:14
供稿:網(wǎng)友
微軟公司給c#(讀為c-sharp)賦予c++某些面向?qū)ο蟮谋举|(zhì),比如模板,但改變了類的創(chuàng)建方法。本文,我將對比c++和c#的類,并著重說明微軟在c#中類創(chuàng)建和使用方面的改變。
一、簡介
面向?qū)ο?oo)編程在應(yīng)用設(shè)計(jì)中已經(jīng)發(fā)展二十來年了。程序不再是一系列函數(shù)的堆徹(象一些范例那樣的程序),而是對象的集合,每個(gè)對象都有其獨(dú)特的屬性和方法來與其它對象打交道。
"c"語言系列是面向?qū)ο笤O(shè)計(jì)發(fā)展的最好例子。c++為開發(fā)者提供了優(yōu)秀的面向?qū)ο缶幊坦ぞ撸绦騿T可以顯式地創(chuàng)建構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),重載操作符,使用模板等等。
象c++這樣復(fù)雜語言的主要問題是程序員要花上好幾個(gè)月來掌握面向?qū)ο笤O(shè)計(jì)本質(zhì)。新程序員必須學(xué)會掌握模板,函數(shù)重載,當(dāng)然還要會創(chuàng)建和使用功能良好的類。
微軟公司給c#(讀為c-sharp)賦予c++某些面向?qū)ο蟮谋举|(zhì),比如模板,但改變了類的創(chuàng)建方法。本文,我將對比c++和c#的類,并著重說明微軟在c#中類創(chuàng)建和使用方面的改變。
本文對象是熟練的c++程序員,通過一些細(xì)節(jié)來解釋c#面向?qū)ο蟮谋举|(zhì)。
二、c#的類有了哪些改變?
如你所知,c#是部分基于c++,部分基于java語法的語言。c#中還有一些細(xì)節(jié)上的改變,使得它可以用于現(xiàn)代設(shè)計(jì)。
當(dāng)你開始用c#建類時(shí)就會立即看到這點(diǎn)。讓我們通過一個(gè)簡單的例子開始了解在c++和c#中是如何建類并進(jìn)行實(shí)例化的。
c++版本:
#include <iostream>
class myclass
{
public: void dosomething()
{
std::cout << "this is some text";
}
};
void main()
{
myclass mc;
mc.dosomething();
}
c# 版本:
using system;
class myclass
{
public void dosomething()
{
console.writeline("this is some text");
}
}
class entrypoint
{
public static void main()
{
myclass mc = new myclass();
mc.dosomething();
}
}
上面的代碼中有幾個(gè)不同之處。
首先,c++用#include包含語句來指明包含文件iostream.h的物理路徑。c#則告訴編譯器程序?qū)⒃趕ystem命名空間下操作,所有的命名空間和類都屬于system命名空間。c#通過命名空間的名字來決定程序的作用范圍(本例中只有system一個(gè)命名空間),而不用指明物理路徑的包含文件方法。
其次,c#的主程序用main(注意m是大寫)。
第三,c++的類聲明結(jié)束后要在最后的大括號后面用分號結(jié)尾。c#則可用可不用,往往都是省略。
第四,你能看到在c#中必須顯式地聲明方法和成員的作用域。若不加聲明,缺省為私有(只有類成員可以訪問),這點(diǎn)與c++一樣。c#中有5種作用域:
公有(public):其他類成員也可以訪問
私有(private):只有類成員才能訪問
保護(hù)(protected):類成員和繼承類成員可以訪問
內(nèi)部(internal):只有匯編里的成員才能訪問(c#的匯編是代碼和資源數(shù)據(jù)的結(jié)合,以asmx作文件后綴)
內(nèi)部保護(hù)(protected internal):類成員和繼承類成員可以訪問
最后,與java一樣,c#的方法也可以聲明為靜態(tài)(static)的。靜態(tài)變量的使用在c#和c++是一樣的。在c#里,可以這樣創(chuàng)建并調(diào)用類的靜態(tài)方法:
using system;
class myclass
{
public static void dosomething()
{
console.writeline("this is some text");
}
};
class entrypoint
{
public static void main()
{
myclass.dosomething();
}
}
注意,這里直接使用類聲明而沒有創(chuàng)建類的實(shí)例。這是為c#語言增加的非常便利的使用方法,可以節(jié)省我們的時(shí)間和內(nèi)存。就是說,不要?jiǎng)?chuàng)建類實(shí)例,可以直接調(diào)用類的方法。
三、用類修飾語限制對類的訪問
以前只能對類成員和類方法設(shè)定限制,但不能對類實(shí)體作限制。c#可以通過聲明類修飾語來對類的實(shí)例實(shí)行限制,如上節(jié)提到的作用域。
c++不能對整個(gè)類作限制。看一下c++的類聲明:
class car
{
public:
car();
car(car &c);
virtual ~car();
private:
int numcars;
car* previous;
car* next;
};
這里有二種訪問類型:公有(public)和私有(private)。繼承或?qū)㈩恈ar實(shí)例化后,程序只能繼承這些代碼,不能作其它變動(dòng),如果要作其它變動(dòng)就不能將其作為基類。
c#對此了改變。可以附加訪問修飾語來限制類成員和方法以及類實(shí)例的訪問權(quán)。c#設(shè)定8個(gè)訪問權(quán)限:
公有(public):可以被所有其它的類訪問。沒有其它限制修飾語,它的公有性質(zhì)就一直是缺省的。
私有(private):只有類成員才能訪問。
保護(hù)(protected):類成員和繼承類成員可以訪問。
內(nèi)部(internal):只有匯編里的成員才能訪問(c#的匯編是代碼和資源數(shù)據(jù)的結(jié)合,以asmx作文件后綴)。
內(nèi)部保護(hù)(protected internal):類成員和繼承類成員可以訪問。
密封(sealed):所有繼承類都不能訪問。無論直接或間接地將它作為基類,c#編譯器都會跳錯(cuò)。
抽象(abstract):與c++的虛(virtual)類或虛方法相似,抽象類不能直接實(shí)例化,抽象函數(shù)含有函數(shù)名。但在作為基類或繼承類時(shí)可以使用。
新建(new):用new創(chuàng)建嵌套類,可以隱藏繼承方式,告訴編譯器創(chuàng)建一個(gè)類的新版本。
舉例來說,如果要?jiǎng)?chuàng)建一個(gè)類,并且這個(gè)類不能被作為基類或繼承,那么就要?jiǎng)?chuàng)建一個(gè)密封類:
sealed class car
{
public void paintcar()
{
// code to paint car goes here
}
}
這時(shí)如果要?jiǎng)?chuàng)建一個(gè)繼承類redcar:
internal class redcar : car
{
// won't work.
}
c#編譯器就會跳錯(cuò):
error cs0509: 'redcar' : cannot inherit from sealed class 'car' (不能從密封類'car'繼承)。
四、c++和c#中的虛函數(shù)
c++和c#都支持虛函數(shù)。在下面的c++例子里,有二個(gè)類,分別稱為base(基類)和derived(繼承類):
#include <iostream>
using namespace std;
class base
{
public:
void dowork()
{
cout << "base class working";
}
protected:
virtual void dowork1() = 0;
};
class derived : public base
{
public:
void dowork2()
{
cout << "derived class working";
}
void dowork1()
{
cout << "dervied pure virtual function working";
}
};
void main()
{
derived d;
d.dowork1();
}
基類里有二個(gè)函數(shù),一個(gè)是dowork,另一個(gè)是純虛函數(shù)dowork1。dowork1只能被基類的繼承類使用。在繼承類(公有地繼承于基類)里有一個(gè)新函數(shù)dowork2,和繼承于基類純虛函數(shù)的超越函數(shù)dowork1。
在c#里實(shí)現(xiàn)同樣的功能要更容易些。看下面的c#代碼:
using system;
abstract class base
{
public void dowork()
{
console.writeline("base class working");
}
public abstract void dowork1();
}
class derived : base
{
public void dowork2()
{
console.writeline("derived class working");
}
public override void dowork1()
{
console.writeline("dervied pure virtual function working");
}
};
class entrypoint
{
public static void main()
{
derived d = new derived();
d.dowork1();
}
}
c#將基類定義為抽象類,將dowork1定義為抽象方法。這樣就可以獲得與上述c++純虛函數(shù)同樣的功能。base類只能作為基類或被含有dowork1超越函數(shù)的繼承類使用。
繼承類在超越抽象函數(shù)dowork1時(shí),在函數(shù)前面加上超越前綴(override)。c#編譯器在發(fā)現(xiàn)繼承類里的override關(guān)鍵字后,就檢查基類的同名函數(shù)。只要不是直接顯式地調(diào)用基類函數(shù),編譯器總是使用繼承類中的方法。
為了讓繼承類直接操作基類成員和方法,c# 為基類命名了一個(gè)別名base。用這個(gè)別名,繼承類可以直接引用基類成員和方法。示例如下:
using system;
class first
{
public void writeit()
{
console.writeline("writing from base class");
}
}
class second : first
{
public second()
{
base.writeit();
}
}
class entrypoint
{
public static void main()
{
second s = new second();
}
}
在上述例子中,有二個(gè)類。一個(gè)是基類(first),另一個(gè)是繼承類(second)。當(dāng)創(chuàng)建second類的實(shí)例時(shí),它的構(gòu)造函數(shù)自動(dòng)調(diào)用基類的writeit方法,用控制臺指令console.writeline打印屏幕。由此引出c++和c#中的多態(tài)性。
五、c++和c#中的多態(tài)性
實(shí)體的多態(tài)性使其具有多種表現(xiàn)形式。在c++和c#中處理多態(tài)性是很相像的。看一個(gè)簡單例子:
c++ 版本:
#include <iostream>
#include <string>
using namespace std;
class person
{
public:
person()
{
classtype = "person";
}
friend void showtype(person& p);
private:
string classtype;
};
class manager : public person
{
public:
manager()
{
classtype = "manager";
}
friend void showtype(person& p);
private:
string classtype;
};
void showtype(person& p)
{
cout << p.classtype << endl;
}
void main()
{
person p;
manager m;
showtype(p);
showtype(m);
}
c# 版本:
using system;
class person
{
public person()
{
classtype = "person";
}
public string classtype;
}
class manager : person
{
public manager()
{
classtype = "manager";
}
public new string classtype;
}
class entrypoint
{
public static void showtype(ref person p)
{
console.writeline(p.classtype);
}
public static void main()
{
person p = new person();
person m = new manager();
showtype(ref p);
showtype(ref m);
}
}
在上面的例子里,有一個(gè)基類person,一個(gè)繼承于基類的manager類。在entrypoint類里,創(chuàng)建了一個(gè)靜態(tài)函數(shù)showtype,其表達(dá)為:
public static void showtype(ref person p)
注意參數(shù)里的ref關(guān)鍵字。ref告訴c#編譯器向showtype函數(shù)傳遞一個(gè)參數(shù)的引用(reference)。在c#中,如果不用ref關(guān)鍵字,函數(shù)的參數(shù)傳遞缺省為值(value)傳遞,將拷貝一個(gè)參數(shù)值傳遞到函數(shù)中去。
在c++中的參數(shù)引用傳遞表達(dá)為:
void showtype(person& p)
c++用"&"符號表示參數(shù)引用使得程序員新手感到困惑,尤其是那些從vb轉(zhuǎn)過來的人。
在c#的主函數(shù)(entry point)里,創(chuàng)建了二個(gè)新的person對象,p和m:
person p = new person();
person m = new manager();
值得一提是,關(guān)鍵字new在c#和c++中用法是不一樣的。在c#里,new只創(chuàng)建一個(gè)對象實(shí)例。這個(gè)對象依然創(chuàng)建在管理堆里,但不返回指向?qū)ο蟮膬?nèi)存地址的指針。在上面的c#例子中,創(chuàng)建了二個(gè)person類對象。第二個(gè)對象,m,卻是manager類的對象。它使用manager的構(gòu)造函數(shù)而不是用person的構(gòu)造函數(shù)。
將person類對象和manager類對象引用到showtype函數(shù),記住,manager是person的繼承類,但c#的多態(tài)性將其表達(dá)為一個(gè)person類:
showtype(ref p);
showtype(ref m);
當(dāng)作用到showtype函數(shù)時(shí),它只處理person對象。c#告訴它說m是person繼承類的對象,它就將m按person類處理了。所以用p和m作參數(shù)調(diào)用showtype函數(shù)后得到的輸出為:
person
person
[譯者注:這樣解釋多態(tài)性有點(diǎn)離譜。這段 c#代碼的真正含義在于詮釋靜態(tài)函數(shù)的作用,而不是什么多態(tài)性。上面一段c++代碼則可以看成多態(tài)性用法的解釋。]
六、結(jié)論
在我熟悉c#之前,我用了4年vb和2年c++。我可以負(fù)責(zé)地說,c#是我用過的語言中最具活力和靈活性并使人愉快的語言,而且它是100%面向?qū)ο蟮摹?br>
如果你是一個(gè)c++程序員,現(xiàn)在想轉(zhuǎn)向電子商務(wù)編程或干脆就是想換一種更現(xiàn)代的語言,那么就是c#了。有這么三種原因:
如果會使用c#,你就能創(chuàng)建任何應(yīng)用:windows應(yīng)用,控制臺應(yīng)用,web應(yīng)用和web服務(wù)等等。
所有的.net平臺使用的語言都編譯成為中間語言(il),并能按照系統(tǒng)環(huán)境進(jìn)行優(yōu)化。
非常非常容易將c++轉(zhuǎn)換成c#。
發(fā)表人信箱: [email protected]