从C转入C++
C++是C的超集(C的扩展名一般为.CPP),在大都分时候,C程序可在C++编译器下运行,但有时会有问题,主要有以下几点:
在C++中可用//表示该符号后面为注释,如:
void main() //这是主函数
在C中以可用以下标识符,但在C++中它们是关键字:
asm
bed_cast
bad_typeid
catch
class
const_cast
delete
dymanic_cast
except
finally
friend
inline
namespace
new
operator
private
protected
public
reinterpret_cast
static_cast
template
this
throw
try
type_info
typeid
using
virtual
xalloc
在C中,可在前面无声明和定义时,调用函数(虽会警告). 但在C++中,任何函数在调用前必须声明或定义.
在C中声明函数时,可不带参数,如:
int FuncA();//实际可能有几个参数
而在C++中这仅能中明无参数的函数。
在C中可用旧式的函数定义如:
int FuncA(x,y)
int x;
int y;
{
...
}
而在C++中这是不允许的.
在C中可对任何指针赋void指针,下:
int a;
int *pint;
void *pvoid=&a
pint=pvoid; //C中可以,C++错
C++会出错,因C++无法自动将Word指针变成另一指针类型,可显式转换
pint=(int*)pvoid;
C中enum,srtuct,union可和同范围内的typedef名一致,而在C++由于可只用名称引用struct等结构,如:
struct TypeA
{
...
};
则可用 TypeA x;定义结构型变量x。
固不能与typedef同名,否则编译器不清楚你到底想要定义什么。
另sizeof()也有两个不同点:在C中sizeof('x'),在C中相当于sizeof(int),而在C++中相当于sizeof(char)。另如有枚举
eumu E(x,y,z);
sizeof(x)在C中相当于sizeof(int),而在C++中为sizeof(E)。
C++新特性
局部变量的声明
在C中我们要声明一个局部变量,必须在块的开头任何语句前声明,在C++中你可在程序任何一个位置声明一个变量.因此一般你可在要用某个变量时才声明它,这样便于阅读与维护(你甚至可在for语句中定义)如:
for(int i=0;i<100;i++) //在C中i必须定义在开始处
{
int c=12;
c*=12;
int a; //这在C中可是不行的
...
}
范围分解操作符
我们都知道:在C中,如在内部(如函数内)声明一个与外部变量(如全局)相同的变量时,内部的变量将掩盖外部变量,(此时外部变量存在但不可见).而在C++中这个外部的变量也是可存取的,只要在该变量前加上"::"即可,如:
double a;
...
{
int a; //声明一与外部浮点变量a相同的整型变量a
a=3; //这个a为内部变量,整型的
::a=3.5; //a为外部,浮点型
}
内嵌函数(线上函数)
如在C++中用inline定义一个函数,如:
inline int FuncA(int a) { ...}
则统编译器把对这个函数的调用换成实际的函数码,和宏很类似,但有两个重要的优势:1.调用函数时,编译器检查参数类型,而宏不会.2.如果表达式传递给函数,它只会求一次值.而在宏中它求两次,这有可能带来问题,如:
ABS(--i); 若ABS是内嵌函数它和我们想的一样工作,而如ABS是宏,则i将被减两次,这可能并不是我们希望的.
这类函数主要用在进行大的循环中,以加快速度,或在类中使用.它与一般函数的不同的是,如改变了它,则所有调用它的源文件都要重新编译.
重载函数(我不知为什么有的书把重载称为过载,怪别扭的)
在C中如你要写一个求浮点型和整型变量绝对值的函数据,那你必须写两个不同的函数(虽然它们内部非常的象)就象下面这样:
int AbsI(int i) {...} //整型版的
double AbsD(double i) {...} //浮点版
而在调用时,不能搞错,而在C++中你可在同一程序中多次定义同一个函数(但它们不能有完全一样的形式),则上例可定义成:
int Abs(int i) {...} //整型版的
double Abs(double i) {...} //浮点版
这样在凋用时可用同一个函数名调用,程序会自动调用正确的版本,如:
Abs(3); //整型版
Abs(-3.5) //调浮点版
你也可能有时调用某函数,而每次用的参数个数不一样,也可利用该功能完成.
缺省函数参数
C++可在声明函数时定义缺省参数值来减少一些编程工作,如:
void ShowText(char *text,int length=-1,int color=0);
这样你可用如下的方法调用:
char *t="hello";
ShowText(t,6,3); //这和平时用法一样
ShowText(t,6); //省去一个参数,此时 color=0
ShowText(t);//省了两个参数, length=-1;color=0
调用时不能只省去中间的,如
ShowText(t,,4); //这是错的
它在定义时,还要注意:不能在参数表中部定义一个缺省变量,而它后面又是正常的变量,(要么它后面全是缺省变量,要么把它放在最后)如:
void ShowText(chat *text,int length=-1;int color);//错
缺省变量一经定义不可在同一范围内再定义(即使是一样的)如
void ShowText(char *text,int length=-1,int color=0);//声明
...
void ShowText(char *text,int length=-1,int color=0) //定义,这就是错的
{...}
另:在用缺省变量和重载函数时要注意它们可能造成运行时出错(编译时可能没问题,如有以下定义:
void Display(char *buf);
void Display(char *buf,int length=30);
这看上去没有任何问题,但如有以下的调用,则出错;
Display("hello"); //多义调用,程序不知到底应调哪一个
引用类型
声明为引用的变量其实是另一变量的别名,可用&定义一引用,如
int c;
int &b;
b=c;
此时b为c的别名,即c与b有同样的地址,对b的操作和对c操作是一个效果.它与指针不同,它们是同样的类型.不能将常量赋值给它:如 b=5;//错
也可将函数参数或返回类型声明为引用,如将参数设为引用,如下
int FuncA(int &a);
而有以下调用:
FuncA(b); //则如在函数内改变了a的值,则b的值也发生同样的改变
当然此时不能有如下的调用(把常量赋给了变量)
Func(4);
这除了用于能改变参数的值之外,也常用于参数为结构时(此时不用将整个结构再复制一遍,有利于提高效率,此时最好也将之定义为常量(见后常量介绍)
函数的返回值也可定义为引用,此时函数必须返回一个适当的变量,如:
int a=0;
int &GetA() {return a}
void main()
{
int N;
N=GetA(); //N=0,注N并不是a的引用
GetA()=5; //a=5;相当与a=5
++GetA(); //a=6;相当于++a
}
由于函数的引用是在函数返回后用的,它不能返回已不存在的变量,特别是返回去自动变量,或是参数的引用,如下例是危险的;
int &aa()
{int a;
return a;}
int &bb(int b)
{return b}
这个程序并不产生编译错误,但它们的结果是无法预料的.这类函数可安全的返回全局变量,static,或动态变量(在下面的new/deldet中介绍)
new和delete
C++中一般用new和delete分配和回收内存块,使用new时指定数据类型,由系统分配足以存放指定类型对象(可为各种类型)的内存块,返回该块地址作为该指定类型的指针,如:
int *cc;
char *ch;
cc=new int;
ch=new char[23]; //分配了一个 char型数组(有23个项)
它们可由delete回收,如:
delete cc;
delete[] ch; //[]表示回收整个数组,而不是单个元素.
常量
可用const定义存放常量的变量,如
const a=100;
则a是一个常量,它不能在程序中改变,但常量并不象你想象的那么简单,它并不象#defind:
一.常量和指针:
这也有几种:
1.将指针定义为常量,可随时改变指针的值,但不能改变指针指向变量的值,(相当于只读指针),如:
const int *PCI;
const int a=1;
int b=2;
PCI=&a; //OK!
*PCI=5; //错,不可改动
PCI=&b; //OK!
2.将常量指针定义到非常量变量,此时指针为常量,必须在定义时初始化,此后不能再赋其它地址,但指针指向的变量可变,如:
int a=1;
int b=2;
int *const CPI=&a; //注意这行!
*CPI=5; //OK
CPI=&b; //ERROR,不能改变指针!
3.定义常量指针到常量对象.这时必须在定义指针时初始化,既不能改指针,也不能改指针指向的值.
4.不能将常量的地址赋于非常量的指针
二.常量与引用
可以定义常量对象的引用.它可用常量初始化:
const int a=1;
const int &RCA=a;
也可用变量初始化
int b;
const int &RCB=b;
无论如何都不能用引用改变所指变量的值.
三.常量和函数
定义函数的参数或返回类型为常量.
如将参数中的一般变量定义为常量,没有什么意义,如:
FuncA(const int a); //a本来就不能改变
我们知道若参数为指针或是引用,则这可改变这此变量的值,但有时,我们可能只对参数的值感兴趣(而不想改变它们的值)这时,可用常量定义参数,保证变量的改变不会有什么副作用,如:
funcA(const int *P);
funcB(const int &C); //无论函数如何对P,C操作,原来的值都不会改变.
另前面讲过如函数的参数是引用,则不能用常数为参数调用该函数,但如定义为常量引用,则可以, 如:
void FuncA(const int &r);
void main()
{...
FuncA(5); //还记得前面说的么,如它只是引用,这是错的,而现在它没问题
...}
如函数的返回值是一般变量,则定义返回为常量没有什么意义,但如是指针,或是引用,则使函数不能用返回值来改变指向或引用的变量.例:
const int *funcA()
{ static int p=1; //注意这的static,若为普通变量很危险,见前引用处
++p;
return &p}
const int &funcB()
{static int s=100;//同想请注意这个static
--s;
return s;}
void main()
{int N;
N=*funcA(); //OK,N为一拷贝
N=funcB(); //OK,N也为一拷贝
*funcA()=5; //错,不可改变.
++funcB(); //错,这可参考一下前面"引用"的例子