C++面向对象程序设计
一、从C到C++
1.引用
int n=4;
int & r=n;//r引用了n,r的类型是int &
对某个变量的引用,等价于这个变量,相当于该变量的一个别名。
void swap(int &a,int &b){
int temp;
temp=a;a=b;b=temp;
}
- 定义引用时,一定要将其初始化成引用某个变量
- 初始化后,它就一直引用该变量,不会再引用别的变量了
- 引用只能引用变量,不能引用常量和表达式
引用作为函数的返回值
int n=4;
int & setValue(){return n;}
int main(){
setValue()=40;//返回值是n的引用
cout<<n;//输出40
return 0;
}
常引用
在定义引用时,前面加const关键字,即为“常引用”
int n;
const int &r=n;//r的类型是const int &
const T & 和 T & 是不同的类型!
T & 类型的引用或T类型的变量可以用来初始化const T &类型的引用。
const T & 类型的常变量 const T & 类型的引用则不能用来初始化T & 类型的引用,除非进行强制类型转换。
int n;
const int & r=n;
r=200;//会报错
n=300;//正确
习题
//下面那个程序片段没有错( D )
//A
int n=4;
int & r=n*5;//定义不正确
//B
int n=6;
const int &r=n;
r=7;//不能通过常引用赋值
//C
int n=8;
const int & r1=n;
int &r2=r1;//不能用const int &类型来初始化 int & 类型
//D
int n=8;
int & r1=n;
const int & r2=r1;//正确,可以用int &类型来初始化const int &类型
int a=1,b=2;
int &r=a;//定义引用
r=b;//相当于将2赋值给a <=> a=2
r=7;// <=> a=7
cout<<a<<endl;//输出7
2.const关键字
能用const,就尽量不要用define,const是一种类型,便于类型检查
定义常量
const int MAX_VAL=23;
const char * SCHOOL_NAME="Huazhong University of Science and Technology";
定义常量指针
不可通过常量指针修改其指向的内容
int n,m;
const int *p=&n;
*p=5;//错误
n=4;//正确
p=&m;//正确,常量指针的指向可以变化
不能把常量指针赋值给非常量指针,反过来可以
const int * p1;int *p2;
p1=p2;//正确
p2=p1;//错误,为了避免错误修改,不会将常量指针赋给非常量指针
p2=(int *)p1;//正确,强制类型转换
函数参数为常量指针时,可避免函数内部不小心改变参数指针所指地方的内容
void MyPrintf(const char *p){
strcpy(p,"this");//编译出错,不能修改p中的内容
printf("%s",p);//正确
}
定义常引用
不能通过常引用修改其引用的变量
int n;
const int & r=n;
r=5;//报错,不能通过常引用r修改值
n=4;//正确
习题
下面那种是对的?
(A)常引用所引用的变量,其值不能被修改
错误:不能通过常引用修改,不通过引用修改就没问题
(B)不能通过常量指针,去修改其指向的变量
正确
(C)常量指针一旦指向某个变量,就不能再指向其他变量
错误:可以指向其他变量,但不能通过常量指针修改其指向的内容
3.动态内存分配
(1)用new运算符实现动态内存分配
p=new T;
T是类型名,P是类型为T *的指针。
动态分配处一片大小为sizeof(T)字节的内存空间,并且内存空间的起始地址赋值给P。
int *pn;
pn=new int;//这里 new运算符 返回的类型是int *
*pn=5;
P=new T[N];
T:任意类型名
P:类型为T*的指针
N:要分配的数组元素的个数,可以是整形表达式
动态分配出一片大小为sizeof(T)*N字节的内存空间并且将该内存空间的起始地址赋值给P。
int *pn;
int i=5;
pn=new int[i*20];//这里new运算符返回的是int *类型
pn[0]=20;
pn[100]=30;//发生了数组越界
(2)用delete运算符释放动态分配的内存
用new动态分配的内存空间,一定要用delete运算符进行释放
delete 指针; 必须指向new出来的空间
int *p=new int;
*p=5;
delete p;
delete p;//异常,一片空间不能被delete多次
用delete释放动态分配的数组,要加[ ]
delete [] 指针; 必须指向new出来的数组
int *p=new int[20];//p 的类型为int *
p[0]=1;
delete[] p;
习题
//下面小段程序,哪个是正确的:(C)
//(A)
char *p=new int;//错误,类型匹配错误
p='a';
delete p;
//(B)
int *p=new int[25];
p[10]=100;
delete p;//错误,释放数组应该有[] ,delete [] p;
//(C)
char *p=new char[10];
p[0]='K';
delete [] p;//正确
4.内联函数和重载函数
内联函数
函数调用是有时间开销的。如果函数本身只有几条语句,执行非常快,而且函数被反复执行很多次,相比之下调用函数所产生的这个开销就会显得比较大。
为了减少函数调用的开销,引入了内敛函数机制。编译器处理对内联函数的调用语句时,是将整个函数的代码插入到调用语句处,而不会产生调用函数的语句。
inline int Max(int a,int b){
if(a>b) return a;
return b;
}
函数重载
一个或多个函数,名字相同,然而参数个数或参数类型不相同,这叫做函数的重载。
int Max(double f1,double f2){}
int Max(int n1,int n2){}
int Max(int n1,int n2,int n3){}
函数重载使得函数命名变得简单。
编译器根据调用语句中的参数的个数和类型判断应该调用那个函数。
int Max(double f1,double f2){}
int Max(int n1,int n2){}
int Max(int n1,int n2,int n3){}
Max(3.4,2.5);//调用第一个
Max(2,4);//调用第二个
Max(1,2,3);//调用第三个
Max(3,2.4);//出错,二义性,不确定调用第一个还是第二个函数,如果第一个参数做类型转换则会调用第一个函数,如果第二个参数做类型转换则会调用第二个函数,出现了二义性
函数的缺省参数
C++中,定义函数的 时候可以让最右边的连续若干个参数有缺省值,那么调用函数的时候,若相应位置不写参数,参数就是缺省值。
void func(int x1,int x2=2,int x3=3){}
func(10 );//等效于func(10,2,3);
func(10,8);//等效于func(10,8,3);
func(10,,8);//不行,只能最右边的若干个参数缺省
习题
下面说法正确的是:(D)
(A)多个重载函数的参数个数必须不同。
错误:参数个数可以相同
(B)两个函数,参数表相同,返回值类型不同,它们是重载关系。
错误:属于重复定义函数
?调用一个第二个和第三个参数都有缺省值的函数时,可以不写第二个实参而写第三个实参。
错误:不能跳过第二个,只能最右边的若干个参数缺省
(D)使用内联函数的目的是提高程序的运行速度。
正确
|