Jacob的C++程序員光速入門C#系列:
C++程序員光速入門C#(一):總覽、數(shù)據(jù)類型、運(yùn)算符
C++程序員光速入門C#(二):流程控制、函數(shù)、類
C++程序員光速入門C#(三):繼承、泛型、異常
之前看了一個(gè)很有價(jià)值的系列博客,博主以C++的視角來入門C#,個(gè)人感覺非常的棒。雖然是很久以前寫的了,很多新特性都沒有涉及,但作為入門參考學(xué)習(xí)還是很有價(jià)值的。這里我把它重新排版修訂一下,作為讀書筆記,也希望能幫助到讀者。原博客地址: C++程序員快速學(xué)習(xí)C#---(一)
一.Hello world!
隨著.NET的深入人心,作為一個(gè)程序員,當(dāng)然不能在新技術(shù)面前停而止步,面對著c++在.net中的失敗,雖然有一絲遺憾,但是我們應(yīng)該認(rèn)識到,對于c++其實(shí)就不應(yīng)該對其在.Net中的表現(xiàn)有太大的奢望,因?yàn)楫吘顾⒉皇且粋€(gè).Net下的正統(tǒng)語言,.Net應(yīng)該是c#的舞臺,作為一個(gè)c++程序員,我們應(yīng)該慶幸,因?yàn)槲覀儗W(xué)習(xí)c#其實(shí)是簡單的直接的,需要我們接受的新知識其實(shí)不多。相對其他語言來說,我們應(yīng)該可以更加平滑的過渡到c#的開發(fā)中.廢話不多說,現(xiàn)在就讓我們用c++的基礎(chǔ)來學(xué)習(xí)這個(gè)漸漸壯大的新語言-----C#。
對于C#的講解我只講解和C++有區(qū)別的地方,相同的部分我就一帶而過,這樣的對比學(xué)習(xí)可以讓我們在已有知識的前提下快速掌握C#。
一開始學(xué)習(xí)語言大部分的教程都會(huì)用一個(gè)Hello World程序來示范,我們也落入俗套,用Hello World來和C++中做一個(gè)比較。
/******************C++程序**********************/
#include <iostream>
using namespace std;
int main()
{
//C++程序
cout<<"Hello World!"<<endl;
return 0;
}
/********************C#程序*********************/
using System;
namespace HelloWorld
{
class Class1
{
//C#程序
static void Main()
{
Console.WriteLine ("Hello World!");
}
}
}
乍一眼看上去兩者差不多,心中一陣竊喜,可以說C#對語法的定義更加嚴(yán)格一些。
首先對于程序的進(jìn)入點(diǎn),最大的區(qū)別就是Main函數(shù)的開頭必須要大寫。因?yàn)镃#是一個(gè)完全面向?qū)ο?/strong>的程序語言,所以它的所有代碼都必須定義在一個(gè)類中,Main函數(shù)也不例外。同時(shí)因?yàn)?net程序在編譯運(yùn)行時(shí)都是先轉(zhuǎn)為中間語言,然后中間語言再編譯為機(jī)器語言,這樣的好處有2個(gè)。一,如同Java一樣,寫好的程序可以在不同的系統(tǒng)中運(yùn)行,而不需要改變程序;二,使用不同的語言寫的程序,因?yàn)橐D(zhuǎn)化為相同的中間語言,所以在程序開發(fā)中可以使用不同的程序語言編寫,而相互調(diào)用。
當(dāng)使用不同語言開發(fā)或者進(jìn)行分類開發(fā)時(shí),各自開發(fā)的程序中會(huì)出現(xiàn)相同的變量名,函數(shù)名等,所以在寫C#程序時(shí),必須把程序包涵在一個(gè)名字空間內(nèi)。C++在多文件編程的時(shí)候出現(xiàn)重復(fù)的變量名的時(shí)候,會(huì)比較頭疼,C#則沒有這個(gè)問題,因?yàn)樗械念惗x都要在一個(gè)命名空間里,而變量只能定義在類中,不存在所謂的全局變量。
定義名字空間使用關(guān)鍵字:namespace <空間名>,當(dāng)一個(gè)命名空間中的代碼需要使用在另一個(gè)名字空間中定義的名稱,就必須包括對該命名空間的引用,使用點(diǎn)字符(.) 。
/********************C#程序*********************/
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
LevelOne.A a1 = new LevelOne.A();
a1.a = 10086;
LevelOne.LevelTwo.A a2 = new LevelOne.LevelTwo.A();
a2.a = 10086;
}
}
namespace LevelOne
{
class A
{
public int a;
}
namespace LevelTwo
{
class A
{
public int a;
}
}
}
}
這里就定義了兩個(gè)名字相同的變量,我們可以使用LevelOne.A 和 LevelOne.LevelTwo.A 來獨(dú)立創(chuàng)建兩個(gè)對象,它們互不干擾。建立了名字空間后,我們可以使用using關(guān)鍵字來簡化對它們包含的名稱的訪問。和C++中使用using namespace std的含義相似。
對于主函數(shù)必須要有限定詞static 這表明Main函數(shù)是靜態(tài)的,在內(nèi)存中只能有一個(gè)副本。
第一行中的using System.其命名空間是.NET應(yīng)用程序的根名字空間,包涵了控制臺應(yīng)用程序所需要的所以基本功能。就如同C++中的頭文件包涵在std這個(gè)名字空間中一樣。
Console.WriteLine ("Hello World!");
Console是system名字空間中的一個(gè)類,其有一個(gè)WriteLine方法,它的作用和cout一樣,輸出一行字符串。
二.數(shù)據(jù)類型
C#中的數(shù)據(jù)類型和C++是類似的。
1.浮點(diǎn)類型
浮點(diǎn)類型中添加了一個(gè)精度更高的decimal類型,對于金融方面的程序開發(fā),此種數(shù)據(jù)類型用來定義錢幣.
2.bool類型
bool類型的變量只能賦值為false和true。雖然它們的含義仍然是0和非0,但是在使用中不能再給它們賦值成整數(shù)值,在判斷語句中 if (bool a==1) 的使用都是錯(cuò)誤的。這樣的語法讓bool類型的意義更加準(zhǔn)確。
3.字符類型
char類型在C#中是16位的,它不能接收一個(gè)整數(shù)值,這與C++有所不同。
4.整數(shù)類型
整數(shù)類新中添加了byte(8位無符號整數(shù)),sbyte(8位有符號整數(shù)),short(16位有符號整數(shù)) 類型
long變成了真正的64位有符號整數(shù),它可以用在64位機(jī)器的編程中。
uint,ushort,ulong顧名思義是沒有符號的整數(shù),它類似于C++中的unsigned int,名字換了一下而已。
long類型在C++中的大小是根據(jù)編譯器位數(shù)改變的,32位編譯器的時(shí)候是4字節(jié),跟int沒區(qū)別。而64位的時(shí)候才是8字節(jié),坑爹!
5.字符串類型
string類型是字符串類型,它是引用的類型,它的使用方法和C++中string的使用相似,可以進(jìn)行+運(yùn)算(運(yùn)算符重載)。
string類型有一些方法可以給我們使用,類似C++。例如:ToCharArray() 把字符串放入一個(gè)字符數(shù)組中等等,可以在MSDN中查找。
6.類型的轉(zhuǎn)換
C#是一個(gè)強(qiáng)類型的語言,它的數(shù)值類型有一些可以進(jìn)行隱式轉(zhuǎn)換,其他的必須顯式轉(zhuǎn)換,隱式轉(zhuǎn)換的類型只能是長度短的類型轉(zhuǎn)換成長的類型,例如int可以轉(zhuǎn)換成long,float,double,decimal。反之必須顯式的轉(zhuǎn)換。
int a=7;
float b=a; //隱式轉(zhuǎn)換
long c=12L; //和C++一樣必須加上后綴L才能將一個(gè)常量定義為long型
a=(int)c; //顯式轉(zhuǎn)換
使用上面的顯示轉(zhuǎn)換不能用在bool和string類型上,如果希望string或者bool類型和整數(shù)類型之間的轉(zhuǎn)化可以使用一個(gè)方法:
//Convert.To*****(val)
//*****:一種數(shù)據(jù)類型(具體請參看MSDN) val:可以是這種類型的變量
int a=123;
string str=Convert.ToString(a);
bool m_bool=Convert.ToBoolean(a);
7.枚舉類型
C++和C#的枚舉類型,定義相同,使用也相同,只要注意C#中語句最后不需要;結(jié)束符。同時(shí)定義枚舉類型時(shí)也不許放在主函數(shù)代碼段中它只能放在執(zhí)行代碼外面,如下
using System;
namespace HelloWorld
{
class Program
{
enum Week
{ monday=5, tuesday, wednesday,thursday, friday, saturday,sunday }
static void Main(string[] args)
{
int a = (int)Week.tuesday;
//輸出數(shù)字6,Right?
Console.WriteLine(a);
Console.ReadKey();
}
}
}
8.指針類型
c++中奉為經(jīng)典的指針類型,在C#中已經(jīng)取消了,真不知道這個(gè)是一個(gè)好消息還是壞消息,不過在易用性方面來說因該是一個(gè)進(jìn)步。不過c#中其實(shí)在隱藏了一個(gè)指針,我們會(huì)在后面說到,同時(shí)在C#中也可以包含不安全代碼,這些代碼就是使用了指針的代碼。
9.結(jié)構(gòu)類型
C#中的結(jié)構(gòu)類型看上去和C++沒有什么區(qū)別,定義使用也相似,但還有有很大的區(qū)別的,首先就和枚舉類型相似, 最后不需要;結(jié)束符,同時(shí)定義時(shí)也不許放在主函數(shù)代碼段中它只能放在執(zhí)行代碼外面。其二最大的區(qū)別就是C#中的結(jié)構(gòu)已經(jīng)和類相似了,不同的地方在于:C++中的結(jié)構(gòu)中成員變量是公有的,而C#中是私有的,C#中的結(jié)構(gòu)和類的區(qū)別唯一就是不能繼承(但是可以有接口,這個(gè)以后會(huì)講到),但是C#結(jié)構(gòu)是在堆棧中創(chuàng)建的空間,所以最好是對小量的數(shù)據(jù)進(jìn)行操作。
/**********************C#程序************************/
using System;
namespace HelloWorld
{
class Program
{
public struct Student
{
public int intVar;
public double doubVar;
}
static void Main(string[] args)
{
Student a, b;
a.intVar = 1;
a.doubVar = 1.1;
b = a;
a.doubVar = 2.6;
Console.WriteLine("{0} {1} {2} {3}", b.doubVar, b.intVar, a.intVar, a.doubVar);
Console.WriteLine("{1} {0} {3} {2}", b.doubVar, b.intVar, a.intVar, a.doubVar);
}
}
}
/*********************************
輸出結(jié)果:
1.1 1 1 2.6
1 1.1 2.6 1
**********************************/
/*******************************
//C#中的結(jié)構(gòu)類型不能繼承!
struct A
{ }
//ERROR?。? struct B:A
{
}
class C
{ }
//YES!
class D : C
{
}
********************************/
C#中的輸出定位格式和C語言中的printf類似,但更加簡潔,不需要在對不同類型的變量使用不同的占位符,只需對應(yīng)后面跟著的變量,給出序號就可以了。
10.數(shù)組類型
數(shù)組的定義和C++有區(qū)別,看上去很別扭,定義語法為:
<類型>[] <變量名> 例: int[] num;
這樣就定義了一個(gè)int類型的數(shù)組,但是切記它可和C++不同,[]里面可不要寫內(nèi)容哦!int[10] num可是錯(cuò)誤的。確定數(shù)組的大小有兩個(gè)辦法:
一,在定義時(shí)指定數(shù)據(jù)
int[] num = {5,3,7,3};
二,使用關(guān)鍵字new,例:
int[] num = new int[4];
當(dāng)然兩者也可以合起來,例:
int[] num = new int[4]{5,3,7,3};
注意:前面定義了4個(gè)數(shù)據(jù),后面花括號里面就必須有4個(gè)數(shù)據(jù),不然就是錯(cuò)誤的。
//錯(cuò)誤!!
//int [] num = new int[4]{4,3};
并且,對多維數(shù)組的定義和C++是不同的。C++中定義為
int num[3][4] = {1,2,3,4,5,3,2,3,4,2,3,4};
C#中定義為
int[,] num = new int[3,4]{{1,2,3,4},{5,3,2,3},{4,2,3,4}};
注意,和C++不同C#不能在數(shù)據(jù)列表中不分類,也就是說不使用{}把一組括起來是錯(cuò)誤的,而在C++中是正確的。
//ERROR to C#!!!
//int[,] num=new int[3,4]{1,2,3,4,5,3,2,3,4,2,3,4};
對數(shù)據(jù)的使用和賦值也相應(yīng)的變?yōu)?/p>
//C#的數(shù)組成員使用和賦值
num[2,1]=3;
//C++的數(shù)組成員使用和賦值
num[2][1]=3;
C#在數(shù)組中最富革命性的改變,應(yīng)該就是是添加了鋸齒形數(shù)組(或者說交錯(cuò)數(shù)組)。例如它可以添加一組{{1,2,3,4},{2,3},{2,3,1}}長度不一樣的數(shù)據(jù),,在C++中只能創(chuàng)建一個(gè)三行四列的數(shù)組,在C#中它能夠產(chǎn)生這樣一個(gè)鋸齒形數(shù)組,第一組中有4個(gè)數(shù)據(jù),第二組中有2個(gè)數(shù)組,第三組中有3個(gè),這樣可以不浪費(fèi)內(nèi)存。

鋸齒數(shù)組的定義和前面的定義也有區(qū)別,它更像是一個(gè)數(shù)組中包含了一個(gè)數(shù)組
int[][] num = new int[3][];
num[0] = new int[4]{1,2,3,4};
num[1] = new int[2]{2,3};
num[2] = new int[3]{2,3,1};
下面是上面的定義的一種簡潔寫法:
int[][] sum = {new int[]{1,2,3,4}, new int[]{2,3}, new int[]{2,3,1}};
三.變量
變量的使用和作用域和C++類似,沒有什么特別需要注意的。但是首先我們應(yīng)該看到,C#是一門完全面向?qū)ο蟮恼Z言,也就是說定義的變量都變成了類的私有成員(定義時(shí)如果沒加訪問修飾符的話)。如果要在別的類中使用變量就需要在定義語句前加上訪問修飾符public。
在C#中必須給每個(gè)變量添加訪問修飾符
public int a;
public int b;
C#中的訪問修飾符還有一些,如下:
internal:變量只能在當(dāng)前程序中使用.
new:在用作修飾符時(shí),new 關(guān)鍵字可以顯式隱藏從基類繼承的成員。
private:私有的,和C++中含義一樣
protected:保護(hù)類型,和C++中含義一樣
static:靜態(tài)的,和C++中含義一樣
readonly: 只讀,在變量初始化(構(gòu)造函數(shù))以后就不許改變.
protected internal:雙重限定,但只有這一個(gè)組合
訪問修飾符new的用法如下
public class Program : BaseClass
{
new public class Test//2、new修飾符 顯式隱藏從基類繼承的成員
{
public int x = 2;
public int y = 20;
public int z = 40;
}
static void Main(string[] args)
{
var c1 = new Test();//1、new操作符 創(chuàng)建對象和調(diào)用構(gòu)造函數(shù)
var c2 = new BaseClass.Test();
Console.WriteLine(c1.x);//2
Console.WriteLine(c2.y);//10
Console.ReadKey();
}
}
public class BaseClass
{
public class Test
{
public int x = 0;
public int y = 10;
}
}
四.常量
C#有兩種常量,一種是const修飾的,一種是readonly修飾的。
const和readonly的區(qū)別是:
1.readonly為運(yùn)行時(shí)常量,程序運(yùn)行時(shí)進(jìn)行賦值,賦值完成后便無法更改,因此也有人稱其為只讀變量。const為編譯時(shí)常量,程序編譯時(shí)將對常量值進(jìn)行解析,并將所有常量引用替換為相應(yīng)值。
2.readonly常量只能聲明為類字段(即C++中的成員變量),支持實(shí)例類型或靜態(tài)類型,可以在聲明的同時(shí)初始化或者在構(gòu)造函數(shù)中進(jìn)行初始化,初始化完成后便無法更改。const常量除了可以聲明為類字段之外,還可以聲明為方法中的局部常量,默認(rèn)為靜態(tài)類型(無需用static修飾,否則將導(dǎo)致編譯錯(cuò)誤),但必須在聲明的同時(shí)完成初始化。
static void Main(string[] args)
{
//OK
const int a = 10;
//ERROR!!
//readonly int b = 10;
}
3.由于const常量在編譯時(shí)將被替換為字面量,使得其取值類型受到了一定限制。const常量只能被賦予數(shù)字(整數(shù)、浮點(diǎn)數(shù))、字符串以及枚舉類型。而readonly則可以修飾類對象。
//ERROR!!
//public const DateTime D = DateTime.MinValue;
//OK
public readonly DateTime D = DateTime.MinValue;
五.運(yùn)算符
C#中的運(yùn)算符,優(yōu)先級和C++一樣,但是需要注意下面的四個(gè)運(yùn)算符
* , -> , & ,sizeof
上面的四個(gè)運(yùn)算符在C#的不安全代碼中可以使用,但在一般的C#代碼中使用是錯(cuò)誤的,C#取消了指針,當(dāng)然和指針有關(guān)的操作符都不能用了。
Reference:
C++程序員快速學(xué)習(xí)C#---(一)
C#高級編程 ——Christian Nagel & Jay Glynn & Morgan Skinner