1.3 C++对C的扩充
1.3.1 C++的输入输出
1. 标准输入输出流cout和cin。在头文件<iostream>。
2. cerr:标准出错输出
clog:cerr的缓冲形式
3. cin>>:>>常称为“提取运算符”。用”>>” 从键盘取得数据并送到输入流cin中,然后再送到内存。
4. 简单的程序:
int mian(){
cout<<”Please enter your name : ”<<endl;
char name[20];
cin>>name;
cout<<”Hello,”<<name<<endl;
return 0;
}
注意:程序中对变量的定义放在了执行语句后面,在C中是不允许的。
C++允许对变量的声明放在程序的任何位置,但必须在使用变量之前。
1.3.2 用const定义常变量
1. 在C中,常用#define指令定义符号常量,如: #define PI 3.14159
实际上,只是在预编译时进行字符置换,把程序中出现的字符串PI 全部置换成3.14159。
预编译之后,程序中就没有PI这个标识符了。
注意:PI不是变量,没有类型,不占用存储空间。
2. 看简单程序:
int a=1,b=2;
#define PI 3.14159
#define R a+b
cout<<PI*R*R<<endl;
输出的并不是3.14159*(a+b)*(a+b),而是3.14159*a+b*a+b,程序因此常常会出错。
C++提供了用const定义常变量的方法,如: const float PI 3.14159
注意:PI具有变量的属性,有数据类型,占用存储空间,有地址,可以用指针指向它,知识在程序运行期间值是固定的,不能改变。
1.3.3 函数原型声明
1. C中,以下三种声明方式都能通过编译:
int max(int x,int y);
int max();
max();
在C++中,如果函数调用的位置在函数定义之前,则必须进行函数原型声明,使编译系统严格检查。
int max(int x,int y);
int max(int,int);
注意:在编译时,只检查参数类型,而不检查参数名。
1.3.4 函数的重载
1. 在C中,规定在同一作用域(例如同一文件模板中),不能有同名的函数
C++ 允许在同一作用域中用同一函数名定义多个函数,但是,函数的参数个数和参数类型不相同。
2. 简单程序:
int max(int a,int b, int c){
if(b>a) a=b;
if(c>a) a=c;
return a;
}
float max(float a,float b, float c){
if(b>a) a=b;
if(c>a) a=c;
return a;
}
int main(){
int a,b,c;
float d,e,f;
cin>>a>>b>>c;
cin>>d>>e>>f;
int m;
m=max(a,b,c);
cout<<”max_i=”<<m<<endl;
float n;
n=max(d,e,f);
cout<<”max_f=”<<n<<endl;
}
系统会根据实参的类型找到与之匹配的函数,然后调用该函数。
1.3.5 函数模板
1. 简单程序:
template<typename T>
T max(T a,T b,T c){
if(b>a) a=b;
if(c>a) a=c;
return a;
}
int main(){
int i1=8,i2=5,i3=6,i;
double d1=56.9,d2=90.765,d3=43.1,d;
i=max(i1,i2,i3);
d=max(d1,d2,d3);
cout<<”i_max=”<<i<<endl;
cout<<”d_max=”<<d<<endl;
}
通用函数定义:
template<class T>
template<typename T>
注意: 它只适用于函数的参数个数相同而类型不同,且函数体相同的情况,如果参数个数不同,则不能用函数模板。
1.3.6 有默认参数的函数
1. float volume(float h,float r=12.5)
实参与形参的结合是从左至右顺序进行的,因此指定默认值的参数必须放在形参表中的最右端,否则出错。
注意:
1. 如果在函数调用前需要函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给出默认值。也就是在调用之前将默认值的信息通知编译系统。由于编译是从上到下逐行进行的,如果在函数调用之前未得到默认值的信息,则编译到函数调用时,会认为实参个数与形参个数不匹配而报错。
2. 一个函数既不能作为重载函数,又作为有默认参数的函数,会出现二义性。
1.3.7 变量的引用
1. int a;
int &b=a;
这就声明了b是a的引用,即a的别名。
注意:
1. 对变量声明一个引用,并不另开辟内存单元,b和a都代表同一变量单元,因此在 建立引用时只有声明,没有定义。
2. 在声明一个引用时,必须同时使之初始化,不能再作为其他变量的引用。
3. 区分是声明引用还是取地址操作:
当&a的前面有类型符时(int &a),必然是引用,如(p=&a)此时是取地址操作。
4. int a=3;
int &b=a;
int &c=b;
此时,整型变量a有两个别名,b和c。
5. 不能建立void类型的引用
因为任何存在的变量都是非void类型。
6. 不能建立引用的数组
char c[6]=”hello”;
char &rc[6]=c;
数组名c只代表数组首元素的地址,本身并不是一个占有存储空间的变量。
7. 可以用const对引用加以限定
int i=5;
const int &a=i;
a=3; //错误
i=3; //合法
并不阻止改变引用所代表的变量的值。
8. int i=5;
const &a=i+3; //合法
此时编译系统这样处理:生成一个临时变量存放表达式的值,引用是该临时变量的别名,如下:
int temp=i+3;
const int &a=temp;
临时变量是内部实现的,用户不能访问。
2. C++ 添加引用主要是利用它作为函数参数,扩充函数传递数据的功能。
在C中,函数参数传递有以下两种情况:
1. 将变量名作为实参(形参和实参不是同一存储单元)
2. 传递变量的指针
在C++中,传送变量的别名。实际上,实参传给形参的是实参的地址。
3. 使用引用和指针变量作为形参的不同:
设立指针变量需要另开辟内存单元,而引用不是独立的变量,不单独占内存单元。
1.3.8 内置函数
调用函数需要时间,如果有些函数频繁调用,会降低程序执行效率。
C++提供内置函数(也叫内联函数,内嵌函数)。即在编译时将所调用的函数的代码嵌入到主调函数中。
inline int max(int a ,int b,int c)
注意:只有对于规模小且频繁使用的函数,才可以大大提高运行效率。
1.3.9 作用域运算符
先看程序:
float a=13.5
int main(){
int a=5;
cout<<a;
return 0;
}
输出5;
如果想输出全局变量,C++提供作用域运算符“::”。
程序改为:
int main(){
int a=5;
cout<<a<<endl;
cout<<::a<<endl;
return 0;
}
“::a”表示全局作用域中的变量。注意:“::”不能访问函数中的局部变量。
1.3.10 字符串变量
1. 字符数组处理字符串外,C++提供了字符串类型定义字符串变量。
string不是C++具有的基本类型(char,int,float,double),它是在标准库中的一个字符串类。
#include<string>
2. char str[10];
str=”Hello”; //错误
string word = ”Canada”; //在定义字符串变量时,不必指定长度
word[2] = ‘m’; //修改后位“Camada”
3. 定义字符串数组(区别于字符数组)
string name[3]={“zhang”,”li”,”wang”};
说明:每个字符串元素中只包含字符串本身的字符不包括“\0”。
疑问:字符串数组中每个元素的长度不同,定义时怎么给数组分配存储空间的呢?
解答:实际上,编译系统为每个字符串分配固定的字节数(4个字节),在这个存储单元中,并不是直接存放字符串本身,而是存放字符串的地址。name[0]存放的是“zhang”的首地址。
1.3.11 动态分配/撤销内存的运算符new和delete
1. 在C语言中,利用malloc和free分配和撤销内存空间的。但是malloc必须指定开辟内存的大小。
在C++中,利用new和delete取代。
new 类型[初值]
delete p;
delete []pt;
注意:用new分配数组空间时不能制定初值。
2. 简单程序:
struct student{
char name[10];
int num;
};
int main(){
student *p;
p=new student;
strcp(p->name,”wang”);
.......
}
说明:
定义一个指向结构体的指针p。用new开辟空间存放一个student类型的变量。执行new后返回一个指向student的指针存放在p中。
如果内存不足,new会返回一个NULL。
new和delete是运算符,不是函数,因此执行效率高。
1.4 C++程序的编写和实现
1. 编写源程序(.cpp)
2. 对源程序进行编译(生成.obj文件)
作用:对源程序进行词法检查和语法检查,error和warning
3. 将目标文件进行连接(生成.exe可执行文件)
将.obj输入内存,与系统提供的库文件等连接。
4. 运行程序
5. 分析结果
2.2 类的声明和对象的定义
1. 类是对象的抽象,而对象是类的具体实例。
2. 用struct声明的类,如果对其成员既不指定private也不指定public,则系统默认认为是公共的。
用class声明的类,如果对其成员既不指定private也不指定public,则系统默认认为是私有的。
3. 一个对象所占的空间只取决于该对象中数据成员所占的空间,而与成员函数无关。
函数的目标代码是存储在对象空间之外的,如果一个类定义了10个对象,这些对象的成员函数对应的是同一个成员函数代码段。(this指针)
4. 如果在类体中定义的成员函数中不包括循环等控制结构,C++系统则会自动对它们作为inline函数来处理。
5. 如果只声明了类而未定义对象,则类的一般成员函数是不占内存的,只有在定义了类对象时,才为数据成员分配空间。