1、C+程序设计,C+基础知识,第2章 C+基础知识,本章学习要点,从C程序到C+程序的发展历程 简单的C+程序 C+的输入输出、数据类型、函数及指针 C+的常变量、引用、名字空间、字符串变量 C+程序的编写和实现,第2章 C+基础知识,本章学习目标,了解从C程序到C+程序的发展历程 对简单的C+程序有整体的感性认识 掌握C+对C的扩充 掌握C+的输入输出、数据类型、函数及指针 掌握C+的常变量、引用、名字空间、字符串变量 熟悉C+程序的编写和实现流程,2.1 从C到C+,C到C+的发展历程,C+3.0,C+1.0,带类的C,89年,增加类的多继承,91年,增加模板,增加异常处理、名字空间、运行时
2、类型识别,97年,成为标准,2.2 简单C+程序,通过简单的C+例子认识C+程序,【例2-1】在屏幕上输出一行字符“Hello C+!”。 /= #include /包含头文件命令 using namespace std; /使用名字空间std int main() cout“Hello C+!“endl; /输出字符串到屏幕return 0; /main函数返回0至操作系统 /=,注意:标准C+程序和C程序的不同 : main函数的返回值为整型 使用cout输出及需要用到的头文件iostream 名字空间,2.2 简单C+程序,C+的函数和C语言的函数非常相似 函数的使用仍然需要先声明后使用
3、。如果函数定义在函数调用之后,则必须在前面声明函数原型,【例2-2】通过函数求两个整数a和b的和。 /= #include /包含头文件命令 using namespace std; /使用名字空间std int sum(int x, int y) return x + y; /求和的函数 int main() int a,b; /定义两个变量a和bcoutab; /等待用户从键盘输入数据couta“+“b“=“sum(a, b)endl; /输出结果信息至屏幕return 0; /main函数返回0至操作系统 /=,2.2 简单C+程序,【例2-3】声明一个关于人的类Person,人的信息包
4、括姓名、性别、年龄, 人可以输入自己的信息,也可以显示自己的信息。 #include /包含头文件命令 using namespace std; /使用名字空间std class Person /类的声明 public: /以下为类的公用成员函数void SetInfo() /公用成员函数SetInfo coutnamesexage; /输入数据至私有数据成员void Show() /公用成员函数Show cout “name : “name; /输出私有成员name的值cout “sex: “sex; /输出私有成员sex的值cout “age: “ageendl; /输出私有成员age的值
5、 private: /以下为类的私有数据成员char name20; /私有数据成员namechar sex2; /私有数据成员sexint age; /私有数据成员age ; /类声明结束,此处必须有分号,2.2 简单C+程序,int main() /main函数 Person person1,person2; /定义Person类的两个对象person1,person2person1.SetInfo(); /对象person1信息输入person2.SetInfo(); /对象person2信息输入person1.Show(); /对象person1信息输出person2.Show();
6、/对象person2信息输出return 0; /main函数返回0至操作系统 ,在main函数中创建例2-3中Person类的对象,并调用对象的方法。,注意: 类的定义和对象的使用的语法形式 类中的成员分为数据成员和成员函数,成员的可见性分为公用和私有 类的概念的理解:类是一种用户自定义数据类型 对象的理解:对象是类类型的变量,2.3 C+对C的扩充,在输入输出方面的扩充 对数据类型的扩充 常变量 在指针方面的扩充 引用的概念 在函数方面的扩充 名字空间的概念 字符串变量,2.3.1 C+的输入输出,C语言输入输出的实现 通过输入输出库函数实现 C语言的输入输出存在着格式复杂、无法保证安全性
7、、无法对自定义类型整体输入输出等缺点C+对C输入输出的扩充 C+的输入/输出(I/O)流类库 “流”的思想 cout、cin对象,、运算符,2.3.2 数据类型的扩展,基本 类型,空类型,引用 类型,指针 类型,构造 类型,C+数据类型,整型、字符型 浮点型 布尔型,枚举、数组 结构体、共用体 类,2.3.3 用const定义常变量,直接常量和符号常量 符号常量的缺点 运行时不分配内存单元 符号常量没有类型,在编译时不进行类型检查 替换后的表达式和预想的表达式是否一致 为了使常量也能像变量那样进行类型检查,C+提供了用const定义常变量的方法 定义常变量的语法: const 类型 变量名;,
8、2.3.3 用const定义常变量,【例2-4】利用常变量计算圆的面积。 /= #include using namespace std; int main() const float PI = 3.14; /定义常变量float radius = 0;coutradius;cout“The area of circle is: “PI*radius*radiusendl;return 0; /=,注意const的位置,一般见到的const的位置可能在类型的前面,但是const也可以在变量名前面,并且两者的含义完全相同。,2.3.4 指针,指针的概念 指针是一个重要概念,如果使用得当可以使程序
9、高效、简洁、紧凑。如果对指针掌握不牢固,编程则会出现意想不到的错误 指针是内存单元的地址 经常所讲的指针是指针变量的简称,是用来存放指针(地址)的变量。 本节重点讨论C+中使用指针需要注意的地方,2.3.4.1 指针与0,空指针 空指针表示“未分配”或者“尚未指向任何地方”的指针 空指针一般用来判断内存分配是否成功 注意:“空指针”与“野指针”的区别 在指针上下文中的常数0被编译成空指针 程序员更常使用符号常量NULL来表示空指针,2.3.4.1 指针与0,【例2-5】指针和0 /= #include using namespace std; int main() int *p = 0; /定
10、义空指针pint *q; /定义野指针qint x = 100; /定义整型变量x并初始化为100/*p = 50; /若执行则编译出错,不能使用空指针*q = 50; /编译通过,但不知把50写到何处p = q = /输出变量x的值 /=,注意编程时养成定义指针时初始化为空指针,使用指针时判断是否为空指针的好习惯,可以减少程序中指针的许多错误。,2.3.4.2 指针与const,【例2-6】指向const变量的指针。 /= #include using namespace std; int main() const int *p = NULL; /定义指向const变量的指针pconst i
11、nt a = 10 ; /定义常变量ap = /=,通过本例可以看到可以改变指向const变量的指针的指向,但是不能通过指针修改指针指向单元内容,2.3.4.2 指针与const,通过本例可以看到可以改变const指针指向单元的内容,但是不能改变const指针的指向。,【例2-7】const指针。 /= #include using namespace std; int main() int a = 10 ; /定义普通变量aint b = 100; /定义普通变量bint * const p = /=,2.3.4.2 指针与const,对于指向const变量的const指针,既不能改变指针指
12、向单元的内容,也不能改变指针的指向。,【例2-8】指向const变量的const指针。 /= #include using namespace std; int main() int a = 10 ;int b = 100;const int * const p = /=,2.3.4.2 指针与const,小结指针和const的关系比较复杂,const有两个位置,可形成三种指针: 1.只在“*”之前有const的指针,称为指向const变量的指针; 2.只在“*”之后有const的指针,称为const指针; 3.“*”前后都有const的指针,称为指向const变量的const指针。,2.3.
13、4.3 void指针,void在作为函数类型和参数类型时为空类型,表示没有返回值或参数。 void修饰指针时称为“无类型指针”,表示该指针可以指向任意类型的变量。 虽然void指针可以指向任意类型的数据,但是在使用void指针时必须对其进行强制类型转换成它所指向单元的实际类型,然后才可以使用,2.3.4.3 void指针,【例2-9】void指针的声明与使用。 /= #include using namespace std; int main() int x = 100;void *p = /=,2.3.4.3 void指针,为什么要使用void指针 因为void指针可以指向任意类型的数据,所
14、以使用void指针时把void指针所指向的数据给抽象化了,这样可以增加程序的通用性 使用void指针的两个例子,void * memcpy(void *dest, const void *src, size_t len);,void * malloc(unsigned int size);,2.3.4.4 new和delete,C语言的动态内存管理 malloc()和free()函数 主要缺点 函数的返回值是void*类型 分配内存单元时根据参数size的值来分配,无法检查错误 分配到的内存单元无法初始化 C+中使用new和delete运算进行动态内存管理,2.3.4.4 new和delete
15、,【例2-11】使用new和delete动态管理内存单元。 /= #include using namespace std; int main() int *p = NULL; /定义整型指针pp = new int; /用new申请可以存放一个整型数据的内存单元cout“*p = “*pendl; /输出指针p指向单元的内容delete p; /delete释放指针p指向内存单元return 0; /=,2.3.4.4 new和delete,申请内存空间并进行初始化 指针变量 = new 数据类型(初值); 分配多个连续变量的存储空间 使用new 和delete 指针变量 = new 数据类
16、型元素个数; delete 指针变量;,三种动态内存管理的方式:兼容C语言的malloc/free方式,单个变量的new/delete方式,多个变量的new /delete 方式,2.3.5 引用,引用就是某一变量的别名,对引用的操作与对变量直接操作完全一样 引用的声明方法 类型标识符 ,“&”运算符在变量的前面表示取地址运算,在赋值运算任的左侧是引用运算符,这种在不同的上下文环境中具有不同含义的现象,称之为运算符功能重载。,2.3.5 引用,【例2-12】使用引用访问变量。 /= #include using namespace std; int main() int x = 100; /定
17、义整型变量xint /=,程序执行后运行的结果如下: rx = 100 x = 200,2.3.5 引用,【例2-13】编写一个函数,交换两个整型变量的值。 /= #include using namespace std; void swap(int /=,通过函数交换两个变量的值有三种形式:值传递、地址传递和引用传递。其中值传递不能实现交换的目的,引用传递和地址传递都可以实现,但引用传递的形式更简单。,2.3.5 引用,引用和const 可以用const对引用加以限制,不允许改变该引用的值 const引用和语法 const 类型标识符 利用常引用作为函数形参,既能提高程序的执行效率,又能保护
18、传递给函数的数据不在函数中被改变,达到保护实参的目的,2.3.5 引用,引用作为函数的返回值,【例2-14】引用作为函数的返回值。 #include using namespace std; int ,由于函数的返回值为引用类型,所以可以为函数赋值,为函数赋的值赋给两个参数中的大者,所以a的值为2,b的值为4,2.3.6 函数,面向过程的C+程序中的函数与C语言中的函数基本相同 面向对象的C+程序中的函数有成员函数和公共函数之分 主要讨论面向过程的C+程序中函数与C语言函数的区别,2.3.6.1 函数原型声明,在函数尚未定义的情况下,先将函数的形式告诉编译系统,以便编译能够正常进行 函数原型声
19、明的语法形式有两种:,(1)返回值类型 函数名(参数类型1, 参数类型2, .); (2)返回值类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, .);,函数原型声明和函数定义是不同的。函数原型声明不是一个独立的完整的函数单位,它仅仅是一条语句,因此在函数原型声明后面一定要加上分号。,2.3.6.2 函数默认参数,在多次调用一个函数将实参传递给形参时,其中可能有一个或几个参数,它们传递进来的实参值多次相同 在定义或声明函数时,给形参一个默认值,如果在调用时没有给该形参传递实参值,则使用默认值作为该形参的值;如果调用时给该形参传递了实参值,则使用实参的值作为该形参的值。,2.3.6.
20、2 函数默认参数,【例2-16】求两个或三个正整数中的最大值,使用带有默认参数的函数实现。 /= #include using namespace std; int main() int max(int,int,int = 0); /带有默认参数的函数原型声明int a = 5,b = 8,c = 10;cout“max of a and b is:“max(a,b)endl;/调用默认参数的函数cout“max of a, b and c is:“max(a,b,c)endl;return 0; int max(int a, int b, int c = 0) /定义带有默认参数的函数 if
21、(a b) a = b;if(a c) a = c;return a; /=,2.3.6.2 函数默认参数,1.指定默认值参数默认值的位置:为了避免混淆,最好只在函数原型声明时指定默认值。 2.当只有部分形参带有默认值时,带有默认值的参数必须放在形参表的右端。 3.当一个函数既是重载函数,又是带有默认参数的函数时,要注意不要出现二义性的问题,注意,调用带有默认参数的函数时,实参的个数可以与形参的个数不同,对于实参未给出的,可以从形参的默认值中获得,利用这一特性,可以使函数的使用更加灵活。,2.3.6.3 函数与引用,函数的参数是引用 当使用引用作为函数的形参时,引用不是一个单独的变量,不需要在
22、内存中分配存储单元,实参向形参传递的是变量的名字,而不是变量的地址。使用引用作为函数的形参可以部分代替指针,降低了程序的复杂度,提高了程序的执行效率,同时也提高了程序的可读性。 函数的返回值是引用,2.3.6.4 函数与const,const修饰函数的参数 调用函数时用相应的值初始化const常量 函数体按照const所修饰部分进行常量化 const修饰函数的返回值 用于二目操作符重载函数并产生新对象 const修饰整个函数 这种情况发生在类的成员函数时 const的位置放在函数参数表的后面,2.3.6.5 函数重载,一般情况下,一个函数名对应一个功能 特殊情况下,一个函数名对应多个功能 功能
23、是非常类似 参数不同,【例2-18】使用add为函数名定义整数的加法和两个浮点数的加法int add(int a,int b) /整数加法的add函数定义 cout“Call integer add function. “endl;return a+b;float add(float a,float b) /浮点数加法的add函数定义 cout“Call float add function. “endl;return a + b;,2.3.6.5 函数重载,函数重载需要函数参数的类型或个数必须至少有其中之一不同,函数返回值类型可以相同也可以不同。但是,不允许参数的个数和类型都相同而只有返回值
24、类型不同。从语法上来说,可以让两个或多个完全不相干的函数使用相同的函数名,进行重载,但是这样做使得程序的可读性下降,不建议这样做。使用同名函数进行重载时,重载函数在功能上应该相近或属于同一类函数。,2.3.6.6 内置函数,调用函数时系统需要一定的时间和空间的开销 当函数体很小而又需要频繁调用时,运行效率与代码重用的矛盾变得很突出 系统在编译时将所调用的内置函数的代码直接嵌入到主调函数中 执行时就不会发生函数调用,而是顺序执行,2.3.6.6 内置函数,【例2-20】将函数声明为内置函数。 /= #include using namespace std; int main() int x =
25、3, y = 5;int s;inline int add(int a, int b); /内置函数原型s = add(x,y); /调用函数addcout“s = “sendl;return 0; inline int add(int a,int b) return a+b; /定义内置函数add /=,2.3.6.6 内置函数,1.在声明内置函数时,可以在函数声明和函数定义的前面都写上关键字inline,也可以只在其中一处写上关键字inline,效果都是相同的。 2.内置函数是一种“以空间换时间”的策略。 3.对函数进行内置声明,只是程序员对编译系统的一个建议而非命令,并不一定只要声明为内
26、置函数C+系统就一定会按内置函数去处理,系统会根据实际情况决定是否这样做。 4.内置函数的机制适用于被调函数规模较小而又被频繁调用的情况,注意,2.3.7 名字空间,1.为什么需要名字空间 引用名字空间的概念就是为了解决程序中名字冲突的问题 2.什么是名字空间 所谓名字空间就是一个由程序设计者命名的内存区域 根据需要指定一些有名字的空间域,把一些全局标识符放在各个名字空间中,从而避免与其他同名的全局标识符混淆,2.3.7 名字空间,3.如何使用名字空间 定义名字空间时,语法如下:其中成员的类型包括:常量、变量、函数、结构体、类、模板等,还可以是名字空间,namespace 名字空间名 定义成员
27、 ,2.3.7 名字空间,定义名字空间举例: namespace ns const int RATE = 0.08;double money;double tax() return money * RATE; namespace ns2int count; ,如果要访问名字空间ns中的成员,可以采用名字空间:成员名的方法,如ns:RATE、ns:money、ns:tax()、ns:ns2:count等,可以看到,在访问名字空间的成员时可能需要写很长的一串名字,使用时不太方便,为此C+提供了一些简化机制,2.3.7 名字空间,访问名字空间中成员的简化机制:,(1)使用名字空间的别名 namesp
28、ace Information . 可以用一个较短的缩写作为别名来代替它。如: namespace Info = Information;,(2)使用using名字空间的成员名 如:using ns:tax; 后面访问tax()时就相当于ns:tax(),(3)使用using namespace名字空间名 如: using namespace ns; 这样在using namespace声明的作用域中,名字空间ns中的成员就好像在全局域声明一样,可以直接使用而不必加名字空间名限定,2.3.7 名字空间,4.无名的名字空间 没有名字的名字空间 由于没有名字空间名,在别的文件中无法访问,它只能在本
29、文件的作用域内有效。相当于将无名名字空间的成员的作用域限制在本文件内 。,namespace void func() cout“func in noname namespace!“endl; ,2.3.7 名字空间,5.标准名字空间std C+系统将标准C+库中的所有标识符都放在名为std的名字空间中定义,即系统预定义的头文件中的函数、类、对象和类模板都是在名字空间std中定义的 一旦使用了名字空间std,就必须保证在程序中不再定义与名字空间中已经出现的标识符同名的量。例如在程序中不能再定义名为cin或cout的对象。,2.3.8 字符串变量,C语言对字符串的处理 C+除保留C语言对字符串的处
30、理方式外,又增加了一种新的类型:字符串类 用字符串类定义的字符串类类型的变量称为字符串变量 字符串变量可以代表一个字符串,而不必去关心字符串的内存分配问题,2.3.8.1 字符串变量定义,定义字符串变量和定义普通变量一样string不是基本数据类型,所以在使用时需要在文件的开头包含C+标准库中的string头文件 注意:头文件的名字是string,而不是string.h,string str1; /定义名字为str1的字符串变量 string str2 = “Hello C+“; /定义名字为str2的字符串变量并初始化,#include ,2.3.8.2 字符串变量赋值,使用字符串变量可以直
31、接使用赋值运算符给字符串变量赋值 在赋值的过程中不必关心赋值的两个字符串的长度是否一致,字符串变量的长度随字符串的长度改变而改变 字符串变量只存储字符串本身的字符,而不包括结束符0 还可以用数组的方式对字符串变量中的某个字符进行操作,str1 = “Hello!“; /使用字符串常量给字符串变量赋值 str1 = str2; /使用另一个字符串变量str2给字符串变量str1赋值,2.3.8.3 字符串变量输入输出,字符串变量可以像普通变量那样使用输入输出流进行输入输出,如: string str1; cin str1; cout str1;,2.3.8.4 字符串运算,字符串复制用赋值号(=),如:str1 = str2; 字符串连接用加号(+),如:str3 = str1 + str2; 字符串比较直接使用关系运算符。可以直接使用=、=、=等关系运算符来进行字符串的比较,2.3.8.5 字符串数组,定义了一个字符串数组strArray并初始化:string strArray5 = “Hello“,“this“,“is“,“C+“,“program“;,2.4 C+程序编写和实现,C+程序的实现与C语言程序实现的过程是一样的 用C+语言编写源程序 (.cpp) 对源程序进行编译 (.obj) 对目标程序进行连接 (.exe) 运行调试程序,Thank You !,