第一章 C++基础
教学目的和任务 通过理论授课和项目实战,使学生掌握C ++程序的全部语法和程序设计的基本方法,能够比较熟练地使用C ++语言编写程序,培养出扎实的软件开发基本技能,并养成良好的编程风格,为进一步学习后续课程和将来从事应用软件开发奠定良好的基础。
基本要求 具备语言、算法、数据结构和程序设计等方面的知识并具有一定的自学能力。 掌握相关工具的使用 Microsoft Visual C++ 6.0 Microsoft Office Visio 2003 掌握面向对象程序设计的基本思想并能运用C ++语言进行程序设计来解决一些具体的问题。
具体安排 C++课程表 理论课安排 项目实战 AA制消费系统 考试安排 项目评审 笔试 机试
学习经验 当天的知识点当天掌握 当天的项目任务当天完成 多思考、多动手、多讨论、多提问 作业点评后,要求对作业做进一步调整 充分利用课外的时间(晚上和周末) 准备一本参考书,每天争取阅读一个章节,补充一些课外的知识
C++参考书 C++程序设计 .钱能 .清华大学出版社 C++程序设计的配套习题和解答 .钱能 . 清华大学出版社 C++ Primer (第三版 ) 作者:Stanley B.Lippman,Josée LaJoie,Barbara E.Moo 出版社:Addison Wesley/Pearson
本章目标 C++ 与 C C++的优点 C++中的数据类型 引用类型 函数重载、参数默认值 C++中的动态内存分配
C++与C的关系和区别 在C++语言中引入了面向对象的思想 是一种混合型的语言,同时支持结构化程序设计和面向对象程序设计方法 允许数据抽象,支持封装、继承和多态等特征
C++的优点 C++适用的应用程序范围极广 C++可以用于硬件级别的编程 错误处理机制 更好的使用COM(ActiveX)与DCOM
C++标准库 2-1 直接使用标准C中所有库,如以下是常用的标准C函数库头文件: stdio.h stdlib.h string.h ctype.h
C++标准库 2-2 C++编译器都提供有完整的标准库 C++标准库中的几乎所有内容都是在命名空间std中定义的
关键字 关键字是系统已经预定义的单词,有专用的定义。这些关键词都是保留字,用户不可再重新定义。 C++区分大小写,关键字全部由小写字母组成。标准C++(ISO14882)定义了74个关键字,具体的C++编译器还会做一些增删 bool wchar_t class friend private protected public asm explicit namespace operator template this typename using virtual throw try delete false new true const_cast dynamic_cast reinterpret_cast static_cast export mutable typeid
数据类型分类 C++中数据有常量和变量之分,它们分别属于以下这 些类型 布尔型(bool) 字符型(char/wchar_t) 基本数据类型 自定义数据类型 布尔型(bool) 字符型(char/wchar_t) 整型(int) 实型 数组型(类型[]) 指针型(类型 *) 构造数据类型 类(class) 空类型(void) 单精度型(float) 双精度型(double) 结构体型(struct) 联合体型(union) 枚举型(enum)
数据类型概述 基本数据类型有4种:整型(int)、实型 (float、double)、字符型(char)、逻辑型(bool) 空类型void:用于显示说明一个函数不返回任何值 构造类型又称为组合类型:是由基本类型按照某种规则组合而成的 指针类型:变量用于存储另一变量的地址,而不能用来存放基本类型的数据 类类型:是体现面向对象程序设计的最基本特征,也是体现C++与C最大的不同之处
bool类型 逻辑型也称布尔型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC++6.0中为1个字节。 声明方式:bool result; result=true; 可以当作整数用(true一般为1,false为0) 把其它类型的值转换为布尔值时,非零值转换为true,零值转换为false
常量说明符const 用const给字面常量起个名字(标识符),这个标识符就称为标识符常量;因为标识符常量的声明和使用形式很像变量,所以也称常变量; 定义的一般形式: const 数据类型 常量名=常量值; 数据类型 const 常量名=常量值; 例如: const float PI=3.14159f; const int Number_of_Student=100; 注意事项: 常变量必须也只能在声明时进行初始化; 常变量初始化之后,不允许再被赋值; 常变量必须先说明后使用; 常变量存储在数据区,并且可以按地址访问,编译时系统对常变量进行类型检查。 C++建议使用常变量,而不要使用#define符号常量。
强制类型转换 强制类型转换格式如下: 作用:将表达式强制转换为type类型,但表达式的值及其类型不变 新增的强制类型转换运算符: type(表达式),例如:int(num); (type)表达式,例如:(int)num; 作用:将表达式强制转换为type类型,但表达式的值及其类型不变 新增的强制类型转换运算符: 格式:static_cast<type>(表达式) 例如:double root=3.14; int value=static_cast<int>(root);
域运算符 C++中增加的作用域标识符 :: #include <stdio.h> int var=1; main(){ 用于对与局部变量同名的全局变量进行访问 用于表示类的成员,这将在关于类的一节中详细说明 #include <stdio.h> int var=1; main(){ int var=0; printf("var=%d\n",var); //局部变量 var=::var; //引用全局变量 printf("after var=::var %d",var); }
动态分配内存 静态分配内存:在编译时确定了固定的内存地址与内存大小,如:函数里的局部变量、全局变量等 动态分配内存:由程序控制,运行时主动性的向系统申请所需大小的内存段,并且每次分配到的内存地址不固定 C++ 可以使用malloc、realloc、calloc和free函数实现,也可以使用运算符new和delete实现
new运算符 new 运算符 可以用于创建堆空间 成功返回首地址,失败返回NULL 语法: 例如: int *p; p=new int; char *pStr=new char[50];
delete运算符 delete运算符 可以用于释放堆空间 语法: delete 指针变量; delete [] 指针变量; 例如: delete p; delete [] pStr;
动态分配内存示例2-1 #include <stdlib.h> #include <stdio.h> int main() { int * a; int i, num; printf("Please enter the number of integers: "); scanf("%d",num); a = new int [num];
动态分配内存示例2-2 if (a == NULL) { printf( "malloc error! exit.\n" ); return 1; } for ( i = 0; i < num; i ++ ) scanf("%d",&a[i]); for (i = 0; i < num; i ++ ) printf( "%5d",a[i] ); printf("\n"); delete [ ] a ; return 0;
函数重载3-1 C++允许用相同的函数名来定义一组功能相同或类似的函数,程序的可读性增强 函数重载又称为函数的多态性 函数重载不同形式: 形参数量不同 形参类型不同 形参的顺序不同 形参数量和形参类型都不同 调用重载函数时,编译器通过检查实际参数的个数、类型和顺序来确定相应的被调用函数
函数重载3-2 合法的重载例子: 非法的重载例子: int abs(int i); long abs(long l); double abs(double d); 非法的重载例子: long abs(int i); void abs(int i); //如果返回类型不同而函数名相同、形参也相同,则是不合法的,编译器会报"语法错误"。
函数重载3-3 #include <stdio.h> int max(int x, int y) double max(double x, double y); void main() { int a=10, b=20 ,c; double x=200.3, y=400.6, z; c = max(a,b); z = max(x,y); printf("%4d%5.1f\n",c,z); } int max(int x, int y) { printf("int function\n"); if(x>y) return x; else return y; } double max(double x, double y) printf("double function\n");
带默认形参值的函数3-1 函数声明或者定义的时候,可以给形参赋一些默认值 调用函数时,若没有给出实参,则按指定的默认值进行工作
带默认形参值的函数3-2 函数没有声明时,在函数定义中指定形参的默认值 函数既有定义又有声明时,声明时指定后,定义后就不能再指定默认值 默认值的定义必须遵守从右到左的顺序,如果某个形参没有默认值,则它左边的参数就不能有默认值。 void func1(int a, double b=4.5, int c=3); //合法 void func1(int a=1, double b, int c=3); //不合法 函数调用时,实参与形参按从左到右的顺序进行匹配
带默认形参值的函数3-3 #include <stdio.h> double power(double x=10.0, int n=2); void main() { printf("power(3,5)=%d\n",power(3, 5)); printf("power(3)=%d\n",power(3)); printf("power()=%d\n",power()); } double power(double x, int n) { int i; double s=1.0; for(i=1; i<=n; i++) s *= x; return s;
带默认形参值的函数的二义性 重载的函数中如果形参带有默认值时,可能产生二义性 #include <stdio.h> int add(int x=5, int y=6); float add(int x=5, float y=10.0); void main() { int a; float b; a= add(10,20); b= add(10); printf("a= %d\n" , a); printf("b= %d\n",b); } int add(int x, int y) { return x+y; } float add(int x, float y) b=add(10)语句产生二义性性,可以认为该语句是调用第一个函数,也 可以是第二个,因此编译器不能确定调用的是哪一个函数。
内联函数2-1 当程序执行函数调用时,系统要建立栈空间,保护现场,传递参数以及控制程序执行的转移等等,这些工作需要系统时间和空间的开销。有些情况下,函数本身功能简单,代码很短,但使用频率却很高,程序频繁调用该函数所花费的时间却很多,从而使得程序执行效率降低。 为了提高效率,一个解决办法就是不使用函数,直接将函数的代码嵌入到程序中。但这个办法也有缺点,一是相同代码重复书写,二是程序可读性往往没有使用函数的好。 为了协调好效率和可读性之间的矛盾,C++提供了另一种方法,即定义内联函数,方法是在定义函数时用修饰词inline。
内联函数2-2 //读入一行字符串,逐个判断是否为数字字符: # include <iostream.h> inline IsNumber(char ch){ return ch>=′0′&&ch<=′9′?1:0; } void main(){ char ch; while(cin.get(ch), ch!= ′\n′) { if (IsNumber(ch)) cout<<″是数字字符 ″<<endl; else cout<<″不是数字字符 ″<<endl; }//因使用频度很高,说明为内联函数。
带参数的宏定义 定义的一般形式: 注意: #define <宏名>(参数表) <字符串> 例如:#define ADD(x,y) (x)+(y) //如果程序中有如下语句 s=ADD(7,8); //则被替换为s=(7)+(8); 注意: 应写在一行上, 若不能写在一行,用续行符“\” 宏名与左括号间不能有空格 宏体中尽量给参数加括号,可以避免替换后在优先级上发生问题
带参数的宏和内联函数的区别 两者的定义形式不一样。宏定义中只给出形式参数,而不指明每一个形式参数的类型;而在函数定义中,必须指定每一个形式参数的类型。 函数调用是在程序运行时进行的,分配临时的内存单元;而宏替换则是在编译前进行的,并不分配内存单元,不进行值得传递处理。 函数调用时,要求实参和形参的类型一致;而宏调用时只用实参简单地替换形参。 使用宏次数多时,宏展开后源程序会变长,因为每一次宏展开都会使源程序增长;而函数调用不使源程序变长。 同样由于宏只做简单的文本替换,并不进行参数类型检查,在C++中建议采用inline函数来替换带参数的宏。
引用类型 引用是一种特殊的变量,可以认为是一个变量的别名。通过引用,我们可以间接地操纵对象 定义引用的一般格式: 类型说明符 &引用名 = 变量名; 例如:int a=1; int &b=a; // b是a的别名,因此a和b是同一个单元 注意:定义引用时一定要初始化,指明该引用变量是谁的别名 对数组只能引用数组元素,不能引用数组(数组名本身为地址)。 不能定义引用的引用(引用也是地址),所以当函数的参数为引用时,引用不能作实参。
按引用传递3-1 引用传递方式是在函数定义时在形参前面加上引用运算符"&" 按值传递方式容易理解,但形参值的改变不能对实参产生影响 例如:swap(int &a,int &b); 按值传递方式容易理解,但形参值的改变不能对实参产生影响 地址传递方式通过形参的改变使相应的实参改变,但程序容易产生错误且难以阅读 引用作为参数对形参的任何操作都能改变相应的实参的数据,又使函数调用显得方便、自然
按引用传递3-2 #include <stdio.h> void swap(int &x, int &y); void main(){ int a, b; a = 10; b = 20; swap(a, b); printf("a=%d,b=%d",a,b); } void swap(int &x, int &y){ int temp; temp = x; x = y; y = temp;
按引用传递3-3 程序运行过程中参数值的变化图示 10 a x b y 20 temp 注意:引用作参数时,函数的实参与形参在内存中共用存储单元,因此形参的变化会使实参同时变化。
总结 本课讲述了以下内容: C++ 与 C的关系 C++的优点 C++中的数据类型 引用类型 函数重载、参数默认值 C++中的动态内存分配