C++.docx
《C++.docx》由会员分享,可在线阅读,更多相关《C++.docx(101页珍藏版)》请在冰点文库上搜索。
C++
C++语言基础
入门简介
变量C++数据类型C++操作符C++中的函数main函数数组字符串数组字符串操作函数
C++是个强大的语言,可以用于做别的语言做不了的工作。
但是,这种强大功能是有代价的。
开始使用C++时,你可能会遇到内存溢出和访问失效等问题,使程序死机。
这里用最简短的篇幅介绍C++语言基础。
C++语言本身有专著介绍,这种书还特别厚,所以别指望我能用三言两语说清楚。
读者学完本书并使用C++Builder一般时间之后,最后对C++语言再作更深入的了解。
C++可以最充分地利用面向对象编程(OOP)的优势。
OOP不只是一个新名词,而有它的实际意义,可以生成可复用的对象。
新术语对象(object),和前面介绍的构件一样,是完成特定编程任务的软件块(构件是对象,但对象不全是构件,稍后会解释这点)。
对象只向用户(使用对象的编程人员)显示必须的部分,从而简化对象的使用。
用户不必知道的所有内部机制都隐藏在幕后。
这一切都包括在面向对象编程的概念中。
OOP可以用模块化方法进行编程,从而避免每次从头开始。
C++Builder程序是面向OOP的,因为C++Builder大量使用构件。
生成构件后(你生成的或C++Builder内置的构件),就可以在任何C++Builder程序中重复使用。
构件还可以扩展,通过继承生成具有新功能的新构件。
最妙的是,构件隐藏了所有内容细节,使编程人员能集中精力充分利用构件。
入门简介
在C++之前先有C语言,C++是建立在C语言之上的,称为“带类的C语言”。
这个C语言基础在当今的C++程序中仍然很重要。
C++并不是取代C,而是补充和支持C。
本章余下部分和下几章主要介绍C++中来源于C语言的部分。
实际上,这里介绍的是C语言,第2课"C++基础"中才转入C++。
读者不必关心哪个来自C,哪个来自C++,因为这些全在C++中。
C++语言很难按顺序介绍,因为我们要介绍的所有特性都是交叉的。
我准备的一次介绍一块,然后拼凑起来。
到第3课"高级C++"结束,你将对C++语言有个完整的了解。
一下子没有掌握某个概念也没关系,有些概念必须经过实践才能完全了解。
变量
还是从变量讲起来吧。
变量(variable)实际上是赋予内存地址的名称。
声明变量后,就可以用它操作内存中的数据。
下面举几个例子进行说明。
下列码段用了两个变量,每条语句末尾用说明语句描述执行该语句时发生的情况:
intx;//variabledeclaredasanintegervariable
x=100;//'x'nowcontainsthevalue100
x+=50;//'x'nowcontainsthevalue150
inty=150;//'y'declaredandinitializedto150
x+=y;//'x'nowcontainsthevalue300
x++;//'x'nowcontainsthevalue301
新术语变量(variable)是留作存放某个数值的计算机内存地址。
注意x的值在变量操作时会改变,稍后会介绍操作变量的C++操作符。
警告声明而未初始化的变量包含随机值。
由于变量所指向的内存还没有初始化,所以不知道该内存地址包含什么值。
例如,下列代码
intk;
inty;
x=y+10;//oops!
本例中变量y没有事先初始化,所以x可能取得任何值。
例外的情况是全局变量和用static修饰声明的变量总是初始化为0。
而所有其它变量在初始化或赋值之前包含随机值。
变量名可以混合大写、小写字母和数字与下划线(_),但不能包含空格和其它特殊字符。
变量名必须以字母或下划线开始。
一般来说,变量名以下划线或双下划线开始不好。
变量名允许的最大长度随编译器的不同而不同。
如果变量名保持在32个字符以下,则绝对安全。
实际中,任何超过20个字符的变量名都是不实用的。
下例是有效变量名的例子:
intaVeryLongVariableName;//alongvariablename
intmy_variable;//avariablewithanunderscore
int_x;//OK,butnotadvisedintX;//uppercasevariablename
intLabe12;//avariablenamecontaininganumber
intGetItemsInContainer();//thanksPete!
说明C++中的变量名是考虑大小写的,下列变量是不同的:
intXPos;intxpos;如果你原先所用语言不考虑大小写(如Pascal),则开始接触考虑大小写的语言可能不太适应。
C++数据类型
新术语C++数据类型定义编译器在内存中存放信息的方式。
在有些编程语言中,可以向变量赋予任何数值类型。
例如,下面是BASIC代码的例子:
x=1;x=1000;x=3.14;x=457000;在BASIC中,翻译器能考虑根据数字长度和类型分配空间。
而在C++,则必须先声明变量类型再使用变量:
intx1=1;intx=1000;floaty=3.14;longz=457000;这样,编译器就可以进行类型检查,确保程序运行时一切顺利。
数据类型使用不当会导致编译错误或警告,以便分析和纠正之后再运行。
有些数据类型有带符号和无符号两种。
带符号(signed)数据类型可以包含正数和负数,而无符号(unsigned)数据类型只能包含正数。
表1.1列出了C++中的数据类型、所要内存量和可能的取值范围。
表1.1C++数据类型(32位程序)
数据类型字节数取值范围
char1-128到126
unsignedchar10到255
short2-32,768到32,767
unsignedshort20到65,535
long4-2,147,483,648到2,147,483,648
unsignedlong40到4,294,967,295
int4同long
unsignedint4同unsignedlong
float41.2E-38到3.4E381
double82.2E-308到1.8E3082
bool1true或false
从上表可以看出,int与long相同。
那么,为什么C++还要区分这两种数据类型呢?
实际上这是个遗留问题。
在16位编程环境中,int要求2个字节而long要求4个字节。
而在32位编程环境中,这两种数据都用4个字节存放。
C++Builder只生成32位程序,所以int与long相同。
说明在C++Builder和BorLandC++5.0中,Bool是个真正的数据类型。
有些C++编译器有Bool关键字,则Bool不是个真正的数据类型。
有时Bool只是个typedef,使Bool等价于int。
typedef实际上建立别名,使编译器在一个符号与另一符号间划上等号。
typedef的语法如下:
typedefintBool;这就告诉编译器:
Bool是int的别名。
说明只有double和float数据类型使用浮点数(带小数点的数)。
其它数据类型只涉及整数值。
尽管integer数据类型也可以指定带小数点的数值,但小数部分会舍弃,只将整数部分赋予整型变量,例如:
intx=3.75;得到的x取值为3。
注意,这个整数值并不是四舍五入,而是放弃小数部分。
顺便说一句,大多数Windows程序很少用到浮点数。
C++可以在必要时进行不同数据类型间的换算。
例如:
shortresult;longnum1=200;longnum2=200;result=num1*num2;这里我想将两个长整型的积赋予一个短整型。
尽管这个公式混用了两种数据类型,但C++能够进行换算。
计算结果会怎样呢?
结果会让你大吃一惊,是25536,这是绕接(wrop)的结果。
从表1.1可以看出,短整型的最大取值为32767,在最大值之上加1会怎么样呢?
得到的是32768。
这实际上与汽车里程计从99999回到00000的道理一样。
为了说明这点,请输入并运行下列清单1.3中包含的程序。
清单1.3Wrapme.cpp
1:
#include
2:
#include
3:
#pragmahdrstop
4:
5:
intmain(intargc,char**argv)
6:
{
7:
shortx=32767;
8:
cout<<"x="<9:
x++;
10:
cout<<"x="<11:
getch();
12:
return0;
13:
}
说明后面几节要介绍的有些清单没有下列语句:
#include
C++Builder生成新的控制台应用程序时会自动加上这条语句。
这在你所用的程序中不是必须的,所以代码清单中将其省略。
无论有无这条语句,程序运行结果是一致的。
分析输出结果为:
x=32767x=32768如果用int数据类型,则不会有这个问题,因为int数据类型的取值范围在正向20亿之间,一般不会有绕回的问题。
但这时程序可能会稍大一些,因为int需要4字节存储,而short只需要2字节存储。
对于大多数应用程序,这个差别是不显著的。
前面介绍了自动类型换算。
有时C++无法进行换算,这时可能在编译器中产生编译错误,说Cannotconvertfromxtoy(无法从x换算到Y)。
编译器也可能警告说Conversionmightlosesignificantdigits(换算可能丢失显著位)。
提示编译器警告应当作编译器错误,因为它表明出了错误。
我们应努力生成无警告的编译。
有时警告无法避免,但一定要认真检查所有警告。
应充分了解警告的原因并尽量予以纠正。
C++操作符
操作符(operator)用于操作数据。
操作符进行计算、检查等式、进行赋值、操作变量和进行其它更奇怪的工作。
C++中有许多操作符,这里不想列出全部,只列出最常用的操作符,如下表所示。
表1.2常用C++操作符操作符说明举例
算术运算符
+加x=y+z;
-减x=y-z;
*乘x=y*z;
/除x=y/z;
赋值运算符
=赋值x=10;
+=赋值与和x+=10;(等于x=x+10;)
-=赋值与减x-=10;
*=赋值与乘x*=10;
\=赋值与除x\=10;
&=赋值位与x&=0x02;
|=赋值位或x|=0x02;
逻辑操作符
&&逻辑与if(x&&0xFF){...}
||逻辑或if(x||0xFF){...}
等式操作符
==等于if(x==10){...}
!
=不等于if(x!
=10){...}
<小于if(x<10){...}
>大于if(x>10){...}
<=小于或等于if(x<=10){...}
>=大于或等于if(x>=10){...}
一元操作符
*间接操作符intx=*y;
&地址操作符int*x=&y;
~位非x&=~0x02;
!
逻辑非if(!
valid){...}
++递增操作符x++(等于x=x+1;)
--递减操作符x--;
类和结构操作符
:
:
范围解析MyClass:
:
SomeFunction();
->间接成员MyClass->SomeFunction();
·直接成员MyClass.SomeFunction();
可以看出,这个清单长了些,没法一下子记住。
使用C++时,你会慢慢熟悉这些操作符的。
必须指出,递增操作符既可用作前递增(++x),也可用作后递增(x++)。
前递增操作符告诉编译器先递增再使用变量,而后递增操作符则让编译器先使用变量值再递增。
例如下列代码:
intx=10;
cout<<"x="<cout<<"x="<cout<<"x="x<cout<<"x="<<++x<输出结果如下:
x=10
x=11
x=12
x=12
递减操作符也是这样,这里不想将这些内容讲得太深,但读者可以耐心阅读下去,正如彭兹对奥古斯特所说,“奥古,耐心点,罗马不是一天建成的”。
说明在C++中操作符可以过载(overload)。
编程人员可以通过过载标准操作符让它在特定类中进行特定运行。
例如,可以在一个类中过载递增操作符,让它将变量递增10而不是递增1。
操作符过载是个高级C++技术,本书不准备详细介绍。
你也许会发现,有些操作符使用了相同的符号。
符号的意义随情境的不同而不同。
例如,星号(*)可以作为乘号、声明指针或取消指针引用。
这初看起来有点乱,事实上,C++编程老手有时也觉得有点乱。
多实践,你会慢慢适应的。
本书有许多例子介绍这些操作符。
读者不必死记每个操作符的作用,而可以在学习中通过程序和码段去理解其作用。
C++中的函数
函数是与主程序分开的码段。
这些码段在程序中需要进行特定动作时调用(执行)。
例如,函数可能取两个值并对其进行复杂的数学运算。
然后返回结果,函数可能取一个字串进行分析,然后返回分析字串的一部分。
新术语函数(function)是与主程序分开的码段,进行预定的一个服务。
函数是各种编程语言的重要部分,C++也不例外。
最简单的函数不带参数,返回void(表示不返回任何东西),其它函数可能带一个或几个参数并可能返回一个值。
函数名规则与变量名相同。
图1.5显示了函数的构成部分。
新术语参数(parameter)是传递给函数的值,用于改变操作或指示操作程度。
返回类型函数名参数表
↓↓↓
intSomeFunction(intx,inty){
函数体→intz=(x*y);returnz;↑返回语句
}
图1.5函数的构成部分使用函数前,要先进行声明。
函数声明或原型(prototype)告诉编译器函数所取的参数个数、每个参数的数据类型和函数返回值的数据类型。
清单1.4列示了这个概念。
新术语原型(prototype)是函数外观的声明或其定义的说明。
清单1.4Muttiply.cpp
1:
#include
2:
#include
3:
#pragmahdrstop
4:
5:
intmultiply(int,int)
6:
voidshowResult(int);
7:
8:
intmain(intargc,char**argv);
9:
{
10:
intx,y,result;
11:
cout<";
12:
cin>>x;
13:
cout<<"Enterthesecondvalue:
";
14:
cin>>y;
15:
result=multiply(x,y);
16:
showResult(result);
17:
cout<18:
getch();
19:
return0
20:
}
21:
22:
intmultiply(intx,inty)
23:
{
24:
returnx*y;
25:
}
26:
27:
voidshowResult(intres)
28:
{
29:
cout<<"Theresultis:
"<30:
}
这个程序的11到14行用标准输入流cin向用户取两个数字,第15行调用multiply()函数将两个数相乘,第16行调用showResult()函数显示相乘的结果。
注意主程序前面第5和第6行multiply()和showResult()函数的原型声明。
原型中只列出了返回类型、函数名和函数参数的数据类型。
这是函数声明的最基本要求。
函数原型中还可以包含用于建档函数功能的变量名。
例如,multiply()函数的函数声明可以写成如下:
intmultiply(intfirstNumber,intsecondNumber);这里函数multiply()的作用很明显,但代码既可通过说明也可通过代码本身建档。
注意清单1.4中函数multiply()的定义(22到25行)在主函数定义码段(8到20行)之外。
函数定义中包含实际的函数体。
这里的函数体是最基本的,因为函数只是将函数的两个参数相乘并返回结果。
清单1.4中函数multiply()可以用多种方法调用,可以传递变量、直接数或其它函数调用的结果:
result=multiply(2,5);//passingliteralvalues
result=multiply(x,y);//passingvariables
showResult(multiply(x,y));
//returnvalueusedasa
//parameterforanotherfunction
multiply(x,y);//returnvalueignored
注意最后一例中没有使用返回值。
本例中调用函数multiply()而不用返回值没什么道理,但C++编程中经常忽略返回值。
有许多函数是先进行特定动作再返回一个数值,表示函数调用的状态。
有时返回值与程序无关,可以忽略不计。
如果将返回值忽略,则只是放弃这个值,而不会有别的危害。
例如,前面的样本程序中忽略了getch()函数的返回值(返回所按键的ASCII值)。
函数可以调用其它函数,甚至可以调用自己,这种调用称为递归(recursion)。
这在C++编程中是个较复杂的问题,这里先不介绍。
新术语递归(recursion)就是函数调用自己的过程。
本节介绍的函数指的是C或C++程序中的独立函数(独立函数不是类的成员)。
C++中的独立函数可以和C语言中一样使用,但C++将函数进一步深化,将在稍后介绍C++时介绍。
函数规则
·函数可以取任意多个参数或不取参数。
·函数可以返回一个值,但函数不强求返回一个值。
·如果函数返回void类型,则不能返回数值。
如果要让返回void类型的函数返回数值,则会发生编译错误。
返回void类型的函数不需包含return语句,但也可以包含这个语句。
如果没有return语句,则函数到达末尾的结束大括号时自动返回。
·如果函数原型表示函数返回数值,则函数体中应包含返回数值的return语句,如果函数不返回数值,则会发生编译错误。
·函数可以取任意多个参数,但只能返回一个数值。
·变量可以按数值、指针或引用传递给函数(将在稍后介绍)。
语法:
函数语句的声明(原型)格式如下:
ret_typefunction_name(argtype_1arg_1,argtype_2arg_2,...,argtype_narg_n);
函数声明表示代码中要包括的函数,应当显示函数的返回数据类型(ret_type)和函数名(function_name),表示函数所要数据变元的顺序(arg_1,arg_2,...,arg_n)和类型(argtype_1,argtype_2,...argtype_n)。
函数语句的定义格式如下:
ret_typefunction_name(argtype_1arg_1,argtype_2arg_2,...,argtype_narg_n);
{statements;
returnret_type;}
函数定义表示构成函数的代码块(statements),应当显示函数的返回数据类型(rettype)和函数名(function_name),包括函数所要数据变元(arg_1,arg_2,...,arg_n)和类型(argtype_1,argtype_2,...argtype_n)。
main()函数
C++程序必须有main()函数。
main()函数是程序的入口点。
前面介绍的每个样本程序都有main()函数。
但是,并非所有C++程序都有传统的main()函数。
用C或C++写成的Windows程序入口点函数称为WinMain(),而不是传统的main()函数。
说明C++BuilderGUI应用程序有WinMain(),但隐藏起来了。
C++Builder使用户无需考虑Windows程序的低级细节,而可以集中考虑程序用户界面和其它部分的创建。
main()函数和其它函数一样是函数,有相同的构成部分。
在32位控制台应用程序中,C++Builder生成具有下列原型的缺省main()函数:
intmain(intargc,char**argv);这个main()函数形式取两个参数并返回一个整型值。
前面说过,数值在调用函数时传递给函数。
但对于main()函数,没有直接调用,而是在程序运行时自动执行。
那么,main()函数如何取得参数呢?
办法是从命令行取得。
现说明如下:
假设有个Win32控制台应用程序要在DOS提示下用下列命令行执行:
grepWM_KILLFOCUS杁-i
这里要用命令行变元WM_KILLFOCUS、d和i启动程序grep,我们要演示如何在main()函数中将其变为argc和argv.首先,整型变量argc包含命令行中传递的参数个数,至少为1,因为程序名也算作参数。
变量argv是个数组,包含字串的指针。
这个数组包含命令行中传递的每个字串。
本例中:
argc包含4
argv[0]包含C:
|cbuilder|bin|grep.exe
argv[1]包含WM_KILLFOCUS
argv[2]包含d
argv[3]包含i
下面用一个小程序验证这个事实。
在C++Builder中生成新的控制台应用程序并输入清单1.5所示的程序。
清单1.5Argstest.cpp
1:
#include
2:
#include
3:
#pragmahdrstop
4:
5:
intmain(intargc,char**argv)
6:
{
7:
cout<<"argv="argc<8.for(inti=0;i9.cout<<"Parameter"<
"<10.cout<11:
getch();
12:
return0;
13:
}
将这个项目存为Argstest,然后不是单击Run按钮,而是选择主菜单中的Project|BuildAll,这样只建立项目而不执行程序。
项目建成后,选择主菜单中的Run|Parameters,在RunParameters对话框RunParameters字段中输入下列内容:
onetwothree"fourfive"six然后单击Run按钮,程序即用所指定的命令行参数运行。
另一种办