问答题 const有哪些作用
【正确答案】
【答案解析】常类型也称为const类型,是指使用类型修饰符const说明的类型。const是C和C++中常见的关键字,在C语言中,它主要用于定义变量为常类型以及修饰函数参数与返回值,而在C++中还可以修饰函数的定义,定义类的成员函数。常类型的变量或对象的值是不能被更新的。
一般而言,const有以下几个方面的作用:
1)定义const常量,具有不可变性。例如:
const int MAX=100;
int Array[MAX];
2)进行类型检查,使编译器对处理内容有更多的了解,消除了一些隐患。例如:voidf(const int i){...}编译器就会知道i是一个常量,不允许修改。
3)避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。同宏定义一样,可以做到不变则已,一变都变。如1)中,如果想修改MAX的内容,只需要定义constint MAX=期望值即可。
4)保护被修饰的东西,防止被意外的修改,增强了程序的健壮性。上例中,如果在函数体内修改了变量i的值,那么编译器就会报错。例如:
void f(const int i)
{
i=10:
}
上述代码对i赋值会导致编译错误。
5)为函数重载提供参考。
class A
{
void f(int i) {...} ∥定义一个函数
void f(int i) const {...} ∥上一个函数的重载
}
6)节省空间,避免不必要的内存分配。例如:
#define PI 3.14159 ∥该宏用来定义常量
const doulbe Pi=3.14159; ∥此时并未将Pi放入只读存储器中
double i=Pi; ∥此时为Pi分配内存,以后不再分配
double I=PI; ∥编译期间进行宏替换,分配内存
double i=Pi; ∥没有内存分配
double J=PI: ∥再次进行宏替换,又一次分配内存
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以const定义的常量在程序运行过程中只有一份复制品,而#define定义的常量在内存中有若干个复制品。
7)提高了程序的效率。编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
引申1:什么情况下需要使用const关键字?
1)修饰一般常量。一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。 例如:int const x=2或const int x=2。
2)修饰常数组。定义或说明一个常数组可以采用如下格式:
int const a[8]={1,2,3,4,5,6,7,8};
const int a [8]={1,2,3,4,5,6,7,8};
3)修饰常对象。常对象是指对象常量,定义格式如下:
class A;
const A a:
A const a:
定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。
4)修饰常指针。
const int *A:∥const修饰指向的对象,A可变,A指向的对象不可变
int const *A:∥const修饰指向的对象,A可变,A指向的对象不可变
int *const A:∥const修饰指针A,A不可变,A指向的对象可变
const int *const A;∥指针A和A指向的对象都不可变
5)修饰常引用。使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下:
const double & v;
6)修饰函数的常参数。const修饰符也可以修饰函数的传递参数,格式如下:
void Fun(const int Var);
告诉编译器var在函数体中的无法改变,从而防止了使用者一些无意的或错误的修改。
7)修饰函数的返回值。const修饰符也可以修饰函数的返回值,返回值不可被改变,格式如下:
const int Fun1();
const MyClass Fun2();
8)修饰类的成员函数。const修饰符也可以修饰类的成员函数,格式如下:
class ClassName
{
public:
int Fun() const;
};
这样,在调用函数Fun()时就不能修改类或对象的属性。
9)在另一连接文件中引用const常量。使用方式有:
extem const int i:
extern const int j=10;
第一种用法是正确的;而第二种用法是错误的,常量不可以被再次赋值。另外,还要注意,常量必须初始化,如const int i=5。
引申2:什么是常引用?
常引用也称为const引用。之所以引入常引用,是为了避免在使用变量的引用时,在毫不知情的情况下改变了变量的值,从而引起程序错误。常引用主要用于定义一个普通变量的只读属性的别名,作为函数的传入形参,避免实参在调用函数中被意外地改变。
const引用的意思是指向const对象的引用,非const引用表示指向非const类型的引用。如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:
const类型标识符 & 引用名=目标变量名;
常引用的主要用途如下:
1)用做普通变量的只读属性的别名。通常这个别名只能获得这个变量的值,而不能改变这个变量的值。
2)用于函数的形参。常引用做形参,可以确保在函数内不会改变实参的值,所以参数传递时尽量使用常引用类型。
如果是对一个常量进行引用,则编译器首先建立一个临时变量,然后将该变量的值置入临时变量中,对该引用的操作就是对该临时变量的操作,对常量的引用可以用其他任何引用来初始化,但不能改变。
关于引用的初始化,一般需要注意以下问题:当初始化值是一个左值(可以取得地址)时,没有任何问题;而当初始化值不是一个左值时,则只能对一个常引用赋值,而且这个赋值有一个过程,首先将值隐式转换到类型T,然后将这个转换结果存放在一个临时对象里,最后用这个临时对象来初始化这个引用变量。例如下面两种使用方式:
1)double& dr=1:
2)const double& cdr=1:
第1)种方法错误,初始化值不是左值,而第2)种方法正确,其对应的执行过程如下:
double temp=double(1);
const double& cdr=temp;
如果对第1)种使用方法进行相应的改造,也可以变为合法,例如:
const int ival=1024;
1)const int &refVal=ival;
2)int &ref2=ival;
在上例中,第1)种方法的引用是合法的,而第2)种方法的引用是非法的。上例中,可以读取refVal的值,但是不能修改它,因为refVal的类型是const,任何对refVal的赋值都是不合法的(const引用是只读的,常量即不能作为左值的量,定义式中赋初值除外)。同时,const引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量,而非const引用只能绑定到与该引用同类型的对象。例如,下述const引用都是合法的。
inti=42;
const int &r=42;
const int &r2=r+i;
在使用const引用进行函数调用的时候,需要注意一个问题,例如下面函数声明:
void bar(string & s);
那么下面的表达式将是非法的:
bar("hello world");
程序示例如下:
#include<iostream>
#include<string>
using namespace std;
void bar(string& s)
{
cout<<s<<endl;
}
int main()
{
bar("hello world");
return 0;
}
程序输出为
hello world
原因在于“hello world”串会产生一个临时对象,而在C++中,临时对象是const类型的。因此上面的表达式就试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应该在能被定义为const的情况下,尽量定义为const。