一、I/O流实现输入输出
在C++中,使用系统预定义的流类对象cin和cout来实现输入输出,且包含头文件方式为:#include <iostream> using namespace std;或者#include <iostream.h>,例:
#include <iostream>
using namespace std;
int main
{
char c;
int v;
cin>>c>>v;
cout<<c<<" "<<a<<endl;
return 0;
}
//----------------------
//输入:'a' 5
//输出:'a' 5
注意:输入时,两个数据之间使用空白符(空格、回车、Tab键);输出时,可以用endl或者"\n"实现换行。
二、使用const定义常量
C语言中通常使用#define来定义一个常量,但宏定义方式定义的常量存在一定的问题:对常量只做简单的替换,不做类型检查,容易出错。在C++中使用const定义符号常量,C++编译器会做严格的类型检查,格式如下:
const [常量类型] 符号常量名 = 表达式;
注意:必须在定义符号常量时就给其赋值,且不能再对其进行修改(包括通过指针),程序运行时,先计算赋值号右边的表达式的值,然后再将该值初始化该符号常量。而在C中,通过const定义的是只读变量(既然是变量,就不可以例如在定义数组时作为数组大小,不可直接对其进行修改,但可以通过指针对其修改)。C++没有像C一样给const常量分配内存单元,const常量被放在一个只读符号表中。
const与指针的结合
指向常量的指针 | 常指针 | 指向常量的常指针 | |
定义形式 | const 类型名 * 指针名=地址值; | 类型名 * const 指针名=地址值; | const 类型名 * const 指针名 = 地址值 |
示例 | int x = 5; const int *p = &x; | int x = 5; int * const p = &x; | int x = 5; const int * const p = &x; |
可修改 | p, x | *p,x | x |
不可修改 | x | p | *p,p |
通常当指针作形式参数时,通过加const限制,保护对应的实际参数,以防止在函数中通过指针修改了实际参数的值。(后面还将涉及const 与引用相结合、常成员、常对象等)。
三、新增的强制类型转换方式
C中:float f = 100.23; int x = (int)f;
C++中仍支持这种格式,但还提供了另外一种更为方便的调用类型转换函数实现:int x = int(f);
四、新增的bool类型
C++中用常量true表示逻辑真,false表示假,同时在需要bool类型的地方仍然可以使用整形、指针等其他类型的值,0对应false,非0对应true值。在默认情况下bool表达式的值输出为1,false为0。C++中的boolalpha操纵符可以使其输出为'true'或'false',noboolalpha操纵符使输出恢复为1或0(用法为:cout<<boolalpha<<b<<noboolalpha<<b<<endl;)。
五、命名空间
C++提供命名空间防止命名冲突(将所有的定义都放到命名空间中,不同的命名空间中的定义名称可以相同,这样在使用时根据使用的是哪个命名空间来决定使用哪个定义)。
1、命名空间的定义
namespace 命名空间名称 { ...; }
2、使用命名空间中的内容
①using namespace std;然后可以使用C++标准库中的所有定义和声明;
②std::xxxx的方式直接使用;
③using namespace std::xxxx;然后使用xxxx;
使用using namespace std;后可以直接使用所有iostream中所有定义的变量和函数。
C++中不以.h作为头文件扩展名,且标准C头文件在C++中被重新命名(去掉.h在文件名前加c,如#include <stdio.h>变为#include <cstdio>),而C++中的.h头文件中,定义和声明通常不放在命名空间里
六、局部变量随用随定义
C++中局部变量的定义和声明可以在程序块的任何位置出现,此时变量的作用域为定义点到该变量所在最小程序块末的范围,如:for(int i = 0;i < SIZE;i++){ ... }。当出现同名局部变量时,按最近范围优先原则处理。
通常,函数代码较长时,在最靠近使用变量的位置定义;而当函数代码较短时,将局部变量集中在函数开始处定义。
七、域解析符::扩大局部变量的可见范围
当局部变量与全局变量同名冲突时,默认全局变量被隐藏而局部变量可见,但C++中可以通过“::全局变量”的方式使用全局变量。(域解析符只对全局变量起作用,不可以用在局部变量的前面)
八、形式参数可带有默认值
C++中允许在函数原型声明(若无声明则在函数定义首部)为1个或多个形式参数指定默认数值(有函数声明时,则必须在声明中指定),且指定顺序为从右向左,而实际参数的给定顺序是从左向右。
注意:默认参数只能给定一次,如果在原型中已给定,则在函数定义中不能再提供默认值,如果是定义在先的函数无需声明原型,则默认参数值就在函数定义的首部直接给出。
九、内联函数
在C中,对于一个较简单的函数,有时用宏来代替,以减少程序执行过程中调用函数所需的时间和空间开销。但因为预处理器进行宏扩展时,只进行文本替换,不考虑代码的语义,存在不安全因素。而C++中增加了内联函数来代替宏定义,增强了安全性,格式如下:
inline 返回类型 函数名(参数列表)
程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来进行替换。因此会增加目标程序代码量,进而增加空间开销,而时间开销上不像普通函数调用时那么大。故它是以目标代码的增加来换取时间点的节省。关于内联函数:
①函数内不允许使用循环语句和开关语句,且递归函数不能用作内联函数;
②内联函数只适合于1~5行的小函数,而大函数的调用和返回的时间开销相对来说微不足道;
③定义在类中的成员函数自动为内联函数,无需加inline关键字。
十、函数重载
在C++语言中,对于功能完全相同或类似,只是在形式参数的个数、类型、顺序方面有区别的不同函数以相同的函数名来命名,该同名函数被称为重载,编译器通过匹配实际参数与同名函数形式参数判断调用哪一个同名函数。
不作为重载的条件:
①参数表完全相同但返回值类型不同;
②参数表相同但存在是否提供默认值的区别(提供相同的实参,但无法判断调用的是哪一个函数);
③形式参数与引用参数(提供相同的实参,但无法判断调用的是哪一个函数)。
本质上来说,判断重载函数是否正确,要保证任何一次的调用都不会引起歧义。
十一、引用
1、引用的概念及使用
引用即给变量起别名,声明一个引用的格式如下:
函数类型 & 引用名 = 一个已定义的变量名;
①在声明一个引用的同时必须对其初始化,且在以后的程序中不可改变这种别名关系;
②系统不会为引用另外分配内存空间,其所代表的变量空间就是引用的空间;
③并不是任何类型的变量都可以有引用,不能建立void类型引用、引用的引用、指向引用的指针、引用数组等。
2、引用作为形式参数
在C++语言中,引用主要用作函数的形式参数,用于在被调用时成为实际参数变量在被调函数中的别名,从而可以通过对引用的访问和修改达到对实际参数变量进行操作的结果。(克服了不能通过值形式参数改变对应实际参数变量的缺陷,且比值形式参数更高效:无需另外分配内存空间和进行传值操作;另外通过指针方式修改实参时,指针变量也会占据一定内存(4个字节或8个字节))。
为防止函数中修改引用形式参数导致修改实际参数,可以在引用形式参数之前加const修饰符使其成为常引用。
注意:与引用形式参数对应的实际参数只能是变量,不能像值形式参数那样对用的实际参数为常量、变量、表达式,形式更多样。
3、引用与指针的区别
引用 | 指针 | |
实质 | 变量(对象)的别名 | 指向变量(对象)的地址 |
初始化 | 必须进行初始化 | 不是必须,事后可以赋值或申请地址 |
可变性 | 一旦成为某变量的别名,程序中不可更改 | 可随时更改,指向不同的变量 |
是否有空值 | 不可为空,必须是某一变量的别名 | 可以获得空指针NULL,表示不指向任何变量 |
占用空间情况 | 不另外占用空间,只是所指代变量的别名 | 另外占用4字节,存放某变量的地址 |
访问方式 | 简洁方便,直接用引用名 | 相对繁琐一些 |
安全有效性 | 安全,总是有效,因为是某一变量的别名 | 不安全,不一定总有效,可能误指或出现野指针 |
实参为数组时,只能使用指针形参而不能使用引用形参。
4、引用作为返回
函数声明格式:
类型名 & 函数名(形式参数表)
①函数可以作为左值(将函数的调用放在赋值号左边,当作变量使用);
②return后面只能是变量,而不能是常量或表达式;
③return后面的变量的内存空间在本次函数调用结束后应当仍然存在,因此局部变量(函数内自定义变量或非引用形式参数)不能作为引用返回;
④一般情况下,引用返回的是该函数中的一个引用形式参数。
注意:如果返回的是局部变量,赋值左边如果为新定义的变量则不会有什么问题(这时应该直接返回局部变量),如果为引用那么该引用(变量名)对应的地址空间已被释放,所以内容是不确定的。
十二、动态内存空间管理
1、用new申请动态内存
数据类型 *p;
①申请某一数据类型的单个空间:
p = new 数据类型;
②申请一组连续的空间以实现动态一维数组:
p = new 数据类型[SIZE];
注意[]与()的区别,如:p = new int[10]和p = new int(10)分别表示申请大小为10的一维int型未初始化的动态数组和申请一个int型动态内存并且初始化为10。
2、用delete释放动态内存空间
①释放单个动态空间:
delete p;
②释放一维数组空间:
delete []p;
☆注意:在释放内存空间之后,一定要将p指向NULL,否则p将成为野指针。
另外,不要将C和C++中申请动态内存和释放动态内存混用。
3、void类型的指针
将void作为指针的类型时,它表示不确定的类型,因此void类型的指针成为一种通用型指针,即任何类型的指针均可直接赋值给void类型的指针变量。
①可以定义void类型指针,但不可定义void类型变量或引用;
②对于已经获得值的void类型的指针变量、利用该指针处理所指向内存中的内容时,必须再进行显示类型转换,否则将会出错。如:
char c = 'A';
void *p;
p = &c;
cout<<*(char *)p<<endl;
十三、C++语言中的异常处理
异常处理格式如下:
try
{
<被进行异常检查的句子>
throw <表达式>或throw;
}
catch(<异常信息类型如int或变量>)
{
<处理异常语句>
}
①try-catch之间不能有任何其它语句;
②一个try块可以对应多个catch块;
如果执行try中的语句时没有发生异常,则跳过catch块直接执行catch后面的程序,否则根据throw抛出的信息与catch子句相匹配,执行该catch中语句。
如果throw抛出的信息没有任何级(throw上级、上上级等)程序处理,异常将会终止程序。