随着.NET的深入人心,作为一个程序员,当然不能在新技术面前停而止步,面对着c++在.net中的失败,虽然有一丝遗憾,但是我们应该认识到,对于c++其实就不应该对其在.net中的表现有太大的奢望,因为毕竟它并不是一个.net下的正统语言,.net应该是c#的舞台,作为一个c++程序员,我们应该庆幸,因为我们学习c#其实是简单的直接的,需要我们接受的新知识其实不多,相对其他语言来说,我们应该可以更加平滑的过渡到c#的开发中.废话不多说,现在就让我们用c++的基础来学习这个渐渐壮大的新语言-----C#
对于C#的讲解我只讲解和C++有区别的地方,相同的部分我就一带而过,.这样的对比学习可以让我们在已有知识的前提下快速掌握C#
一:统窥:
一开始学习语言大部分的教程都会用一个Hello
World程序来示范,我们也落入俗套,用Hello
World来和C++中做一个比较:
C++:
#include
<iostream>
using
namespace std;
void
main()
{
//C++程序
/* C++程序*/
cout<<"Hello World!"<<endl;
}
C#:
using
System;
namespace
HelloWorl
{
class Class1
{
//C#程序
/*C#程序*/
///C#程序
static void
Main ()
{
Console.WriteLine ("Hello World!");
}
}
}
扎一眼看上去两者差不多,心中一阵窃喜,可以说C#对语法的定义更加严格一些.
首先对于程序的进入点,最大的区别就是Main函数的开头必须要大写.因为C#是一个完全面向对象的程序语言,所以它的所有代码都必须定义在一个类中,Main函数也不例外,同时因为.net程序在编译运行时都是先转为中间语言,然后中间语言再编译为机器语言,这样的好处有2个,一.如同Jave一样,写好的程序可以在不同的系统中运行,而不需要改变程序.二.使用不同的语言写的程序,因为要转化为相同的中间语言,所以在程序开发中可以使用不同的程序语言编写,而相互调用.,当使用不同语言开发或者进行分类开发时,各自开发的程序中会出现相同的变量名,函数名等,所以在写C#程序时,必须把程序包涵在一个名字空间内.
定义名字空间使用关键字:namespace
<空间名>.当一个命名空间中的代码需要使用在另一个名字空间中定义的名称,就必须包括对该命名空间的引用,使用点字符(.)
例:
namespace
LevelOne
{
//name “A”defined
Namespace LevelTwo
{
//name
“A”defined
}
}
这里就定义了两个名字相同的变量,我们可以使用LevelOne.A
和
LevelOne.LevelTwo.A 来独立使用它们,互不干扰.
建立了名字空间后,我们可以使用using关键字来简化对它们包含的名称的访问.和C++中使用using
namespace std的含义相似;
对于主函数必须要有限定词static
这表明Main函数是静态的,在内存中只能有一个副本.
第一行中的using
System.其命名空间是.NET应用程序的根名字空间,包涵了控制台应用程序所需要的所以基本功能.就如同C++中的头文件包涵在std这个名字空间中一样.
Console.WriteLine
("Hello World!");Console是system名字空间中的一个类,其有一个WriteLine方法,它的作用和cout一样,输出一行字符串.
二.数据类
C#中的数据类型和C++是类似的.
1.浮点类型
浮点类型中添加了一个精度更高的decimal类型.对于金融方面的程序开发,此种数据类型用来定义钱币.
2.Bool类型
Bool类型的变量只能赋值为:false和true,虽然它们的含义仍然是0和非0,但是在使用中不能再给它们赋值成整数值,在判断语句中.if
(bool a==1) 的使用都是错误的.
3.字符类型
Char类型在C#中是16位的,它也不能接收一个整数值
4.整数类型
整数类新中添加了byte(8位无符号整数),sbyte(8位有符号整数),short(16位有符号整数)
long变成了真正的64位有符号整数,它可以用在64位机器的编程中.
uint,ushort,ulong顾名思义是没有符号的整数,它和C++中的unsigned
int是一样的,名字换了一下而已.
5.字符串类型
String类型是字符串类型,它是引用的类型,它的使用方法和C++中string的使用相似,可以进行+运算
String类型有一些方法可以给我们使用.例如:ToCharArray()
把字符串放入一个字符数组中
Length 返回字符串的长度等等,可以在MSDN中查找.
6.类型的转换
C#是一个强类型的语言,它的数值类型有一些可以进行隐式转换,其他的必须显式转换,隐式转换的类型只能是长度短的类型转换成长的类型,例如int可以转换成long,float,double,decimal.反之必须显式的转换.
例:int
a=7;
float b=a;
//隐式转换
long c= 12L ; //和C++一样必须加上后缀L才能定义为long型不然就为int型了
a=(int)c; //显示转换
使用上面的显示转换不能用在BOOL和string类型上,如果希望string或者bool类型和整数类型之间的转化可以使用一个方法.
Convert.To*****(val)
*****:一种数据类型(具体请参看MSDN)
val:可以是这种类型的变量
例:int
a=123;
string str=Convert.ToString(a);
bool m_bool=Convert.ToBoolean(a);
7.枚举类型
C++和C#的枚举类型,定义相同,使用也相同,只要注意C#中语句最后不需要;结束符,同时定义枚举类型时也不许放在主函数代码段中它只能放在执行代码外面.如下
using
System;
namespace
HelloWorld
{
enum
week
{monday,tuesday,wednesday,thursday,friday,saturday,sunday}
class Class1
{
static void
Main ()
{
week day=week.friday ;
int a=(int)day;
int b=(int)week.saturday
;
}
}
}
8.指针类型
c++中奉为经典的指针类型,在C#中已经取消了,真不知道这个是一个好消息还是坏消息,不过在易用性方面来说因该是一个进步.不过c#中其实在隐藏了一个指针,我们会在后面说到,同时在C#中也可以包含不安全代码,这些代码就是使用了指针的代码.
9.结构类型
C#中的结构类型看上去和C++没有什么区别,定义使用也相似,但还有有很大的区别的,首先就和枚举类型相似,
最后不需要;结束符,同时定义时也不许放在主函数代码段中它只能放在执行代码外面.其二最大的区别就是C#中的结构已经和类相似了,C++中的结构是公有的,而C#中是私有的,它和类的区别唯一就是不能继承,但是结构是在堆栈中创建的空间,所以最好是对小量的数据进行操作
例:
using
System;
namespace
ConsoleApplication1
{
public struct
student
{
public int
a;
public double
c;
}
enum week
{
monday,tuesday,wednesday,thursday,friday,saturday,sunday
}
class Class1
{
static void
Main (string[]
args
{
week day=week.friday ;
int aa=(int)day;
int bb=(int)week.saturday
;
Console.WriteLine ("{0},{1}",aa,bb);
student a,b;
a.a=1;
a.c=1.1;
b=a;
a.c =2.6;
Console.WriteLine ("{0}
{1} {2}
{3}",b.c,b.a ,a.a ,a.c
);
Console.WriteLine ("{1}
{0} {3}
{2}",b.c,b.a ,a.a ,a.c
);
}
}
}
输出结果:
4,5
1.1 1
1 2.6
1 1.1
2.6 1
C#中的输出定位格式和C语言中的printf类似,但更加简洁,不需要在对不同类型的变量使用不同的占位符,只需对应后面跟着的变量,给出序号就可以了.
10.数组类型
数组的定义和C++有区别,看上去很别扭;定义语法为:
<类型>[]
<变量名>
例:
int[] num;
这样就定义了一个int类型的数组,但是切记它可和C++不同,[]里面可不要写内容哦!int[10]
num可是错误的.确定数组的大小有两个办法,一.在定义时指定数据:例
int[] num={5,3,7,3};
二.使用关键字new;例:int[]
num=new int[4];
当然两者也可以合起来:例:int
[] num=new int[4]{5,3,7,3};注意:前面定义了4个数据,后面花括号里面就必须有4个数据不然就是错误的.例:int
[] num=new int[4]{4,3} //错误;
对数据的使用和C++一样.
对多维数组的定义和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#不能在数据列表中不分类,也就是说不使用{}把一组括起来是错误的,而在C++中是正确的
对数据的使用也相应的变为:num[2,1]=3;
C#在数组中最富革命性的改变因该是添加了锯齿形数组,例如它可以添加一组{{1,2,3,4},{2,3},{2,3,1}}长度不一样的数据,在C++中只能创建一个[3][3]的数组,在C#中它能够产生这样一个锯齿形数组,第一组中有4个数据,第二组中有2个数组,第三组中有3个,这样可以不浪费内存
锯齿数组的定义和前面的定义也有区别,它更象是一个数组中包含了一个数组;
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++类似,没有什么特别需要注意的.
但是首先我们应该看到,现在的程序都是包含在类当中了,也就是说定义的变量都变成了类的私有成员,如果要在别的类中使用变量就需要在定义语句前加上限制符public
在C++中我们看到过这样在类中声名变量:
public:
int a;
int
b;
a,b都是公有的,因为使用了public:,但是在C#中这样的语句没有了,我个人认为这样其实很好嘛,简洁明了,呵呵.
在C#中必须给每个变量添加限制符
public
int a;
public
int b;
C#中的限制符还有一些,如下:
internal:变量只能在当前程序中使用.
new:从其他类继承而来的类,并隐藏了该类中的已有字段,这个关键字会在类中介绍.
private:私有的,和C++中含义一
protected:保护类型,和C++中含义一样
static:静态的,和C++中含义一样
readonly:
只读,在变量初始化以后就不许改变.
protected
internal:当前程序中使用,或者在派生当前类型的其它类型中被访问,就是双重限定,但只有这一个组合
四.常量
常量的定义使用const关键字,和C++类似.
它和只读限定符的区别.1.常量是静态的
2.必须在初始化时赋值
真不明白有什么实际的意义,发现C#也是一个累赘的语言,呵呵.
五.表达式
C#中的运算符,优先级和C++一样,但是需要注意下面的四个运算符
*
, ->
, &
,sizeof
上面的四个运算符在C#的不安全代码中可以使用,但在一般的C#代码中使用是错误的,C#取消了指针,想当然和指针有关的操作符都不能用了.
六.流程控制
1.if/if….else语句
这个语句和C++没有区别.但是结合类型定义中所讲的类型转换,这里需要注意一个问题,看程序
bool
a;
if
(a=Getnum())
//假设Getnum返回一个整数值
{
//a为非0
}
else
{
//a为0
}
在C++中上面的代码是正确的,但是在C#中是错误的,一个整数值是不可以赋给BOOL值的,这样做可以增强代码的安全性
2.switch
选择分支语句和C++用法也相当,但是C#中对它的格式更加严格了,每个case语句后面都必须跟上break,不然就是错误的语句,但是也有例外,可以使用臭名昭著的GOTO语句,跳转到下个case语句,这样编译器是不会报错的,当然如果你真的希望有多个条件执行相同语句的话,可以省略写成下面的方法:
switch
(char c)
{
case
‘ua’:
case
‘us’:
case
‘en’:string
language=”English”;break;
}
3.循环语句
C++中的3种循环语句:for
, while
, do…while
和C#中是相同的
但是C#中添加了一种循环语句,在对数组的输出方面的使用非常灵活,
它就是:foreach
它的语法格式:
foreach
(<变量类型>
<变量名>
in <数组名>)
{}
不管是一维还是多维数组,操作都一样方便,它会自动知道数组的大小对其操作,我们不需要关心它是否会溢出.
C#中现在增加了一种变长数组,对它的操作,foreach也可以做到,但格式不同,看下面的例子
例:
using
System;
namespace
ConsoleApplication1
{
class Class1
{
static void
Main (string[] args)
{
int[,] a1=new
int[2,2]{{1,2},{3,4}};
foreach (int
b 1 in
a1)
{
Console.WriteLine ("{0}",b1);//对不变长数组的操作
}
int[][] a2=new
int[2][];
a2[0]=new int[2]{0,1};
a2[1]=new int[3]{3,4,5};
foreach (int[]
b 20 in
a2)
{
foreach (int
b 21 in
b20)
Console.WriteLine ("{0}",b21);//对变长数组的操作
}
}
}
}
对于变长数组的如此操作,是因为a2包含的是一个int[]元素,而不是int元素,想想我们之前讲的变长数组也叫数组的数组,其实是2个数组的欠套.
现在我们再来看一个对foreach的使用:
int[,]
a1=new int[2,2]{{1,2},{3,4}};
foreach
(int b 1 in
a1)
{
b1=3;
//错误
}
为什么错误.还记得上面我说的一句话吗?--”在对数组的输出方面的使用非常灵活”.也许你已经看出来了,是的,foreach语句只能对数据进行输出,因为它是只读的,不能改变任何数组元素的值.
4.跳转语句
C#中的跳转语句和C++中一样
有:goto
, return
, break
,continue
七.函数
讲到C#的函数,觉得有点别扭,因为现在的所以函数都是包含在一个类当中了,这样就和C++中类的方法的用法相似了,所以在C++中的标准函数需要定义的过程也没有了,这样确切的说函数在C#中已经不复存在了,都变成方法了嘛!
首先我们来看一下C#方法的使用的例子
例:
using
System;
namespace
ConsoleApplication1
{
class Class1
{
static void
Main (string[] args)
{
Write();
}
static void
Write()
{
Console.WriteLine ("This is Text");
}
}
}
看上去用法和C++差不多,但是注意static静态限制符,我们可以回想一下C++类的方法的使用
class
my
{
public:
void a(){ b();}
void b(){cout<<"this
is text";}
};
void
main()
{
my a;
a.a ();
}
C++在类中调用自己的方法是不需要加static的,但是在C#中必须加,因为C#是完全面向对象的语言,只有当方法是静态的时候才能够直接调用,不然必须先用类创建一个实例才能调用
1.参数
C#的方法和C++中的函数在返回值,参数传递方面是一样的,唯一的区别是引用的传递.
也许你想起来上面所讲,C#中取消了&操作符,这意味着没有了引用传递了,其实不是没有,而是不用&,改成了ref
例:
class
Class1
{
static void
Main (string[] args)
{
int a=1,b=2;
Console.WriteLine ("{0} {1}",a,b);
change(ref a,ref
b) ;
Console.WriteLine ("{0} {1}",a,b);
}
static void
change(ref int
a,ref int
b)
{
int c;
c=a;
a=b;
b=c;
}
}
输出结果:
1
2
2
1
在形参和实参中加上ref就完成了引用,这样对a,b的值进行了交换
2.方法重载
C#的函数重载和C++一样没有区别
3.结构函数
上面我用了方法,这里是函数,所以它首先不需要关键字static,这个函数是一个结构的函数,它在类的外部,所以不需要static.
例:
struct
mytext
{
public int
num;
public int
text()
{
return num;
}
}
class Class1
{
static void
Main (string[] args)
{
mytext frist;
int a;
frist.num =5;
a=frist.text ();
Console.WriteLine ("{0}",a);
}
}
输出结果:
5
4.作用域
基本上C#的变量作用域和C#没有区别,只要注意一点,对于全局变量,放在Main函数的外面,类的内部,并且和方法一样,必须加上static.
5.委托
委托在C++里面是没有的,它的定义也很难懂,它是一种可以把引用存储为函数的类型.虽然你读了N便也不太明白它讲的意思,那么我们就通过一个程序来看看,它到底有什么功能,它做了写什么事情.
using
System;
namespace
ConsoleApplication1
{
class Class1
{
delegate double
chooes(double num1,double
num2);
static double
add(double num1,double
num2)
{
return num1+num2;
}
static double
odd(double num1,double
num2)
{
return num1-num2;
}
static void
Main (string[] args)
{
chooes process;
bool m_bool=true;
double num;
if (m_bool)
{
process =new chooes
(add);
}
else
{
process =new chooes
(odd);
}
num=process(10,5);
Console.WriteLine ("{0}",num);
m_bool=false;
if (m_bool)
{
process =new chooes
(add);
}
else
{
process =new chooes
(odd);
}
num=process(10,5);
Console.WriteLine ("{0}",num);
}
}
}
首先看到一个不认识的关键字:
delegate
它即使定义委托函数的关键字.delegate
后面跟着的就和C++中的函数定义一样,但是委托函数没有函数体,从程序中你就可以看见.程序中还有2个函数除了函数名字不同外,函数类型,参数都是一样的,委托函数定义后,必须和类一样定义一个实例,然后用关键字new初始化.从初始化中你因该可以看出端倪了,它把另外的函数初始化了给它,哈哈,对了它其实就是别的函数的一个别名嘛,难怪称作引用存储.通过它的委托,它就可以变成不同函数的别名,这样的好处就是.我们不需要知道真正有作用的函数是哪一个,只需要知道一个函数就可以对其他任意的函数进行调用,这样的选择就象一个要使用的”插件”,委托函数的重要用途在windows程序开发中的事件和事件处理中才能完全体现.
|