const各种用法总结

来源:互联网 发布:sql server 权限管理 编辑:程序博客网 时间:2024/05/29 15:10

const各种用法总结 

原文地址:http://www.cnblogs.com/jiabei521/p/3335676.html#2787569

1、const关键字
常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。
1.1 const使用方法
1.1.1 定义const对象
const修饰符可以把对象转变成常数对象,意思就是说利用const进行修饰的变量可以当做常数来使用
任何对该变量的修改都会导致编译错误。
const int bufferSize = 512;
bufferSize = 0;   //Error

const std::string hi = "hello";
const int i,j = 0;   // 错误,i未初始化
注意:因为常量不能被修改,所以定义时必须得被初始化。

类中的const成员变量必须通过初始化列表进行初始化。
class A
{
public:
A(int i);
void print();

const int &r;
private:
const int a;
static const int b;
};
const int A::b = 10;  //类中的静态变量不属于任何对象,它在定义时就有了内存区,应该被初始化,如果
不初始化不使用的话,也不会出错。
A::A(int i):a(i),r(a)
{
}

1.1.2 const对象默为局部变量
在全局作用域里定义非const变量时,它在整个程序中都可以访问,我们可以把一个非const变量定义在一
个文件中,就可以在另一个文件中使用这个变量。
//a.c
int counter; //definition
//b.c
extern int counter;  //use counter from a.h
++conunter;          //increments counter defined int a.h
在全局作用域声明的const变量只存在于那个文件中,不能被其他文件访问。通过指定const变量为extern,就
可以在整个程序中访问const对象。
//a.c
extern const int bufSize = fcn();
//b.c
extern const int bufSize;  //use bufSize from a.h
注意:非const变量默认为extern,要使const变量能够在其他文件中访问,必须在文件中显式指定它为extern。

1.1.3 const引用
const引用是指向const对象的引用:
const int iVal = 1024;
const int &refVal = iVal;  //两者均为const对象
int &ref2 = iVal;    //error,不能使用非const引用指向const对象,将"int &"类型的引用绑定到"const
int"类型的初始值设定项时,限定符被丢弃
可以读取但是不能修改refVal,因此,任何对refVal的赋值都是不合法的。这个限制有其意义,不能直接对iVal
赋值,因此不能通过使用refVal来修改iVal.
const引用可以初始化为不同类型的对象或者初始化为右值,比如字面常量:
int i = 42;
//仅对const引用合法
const int &r = 42;
const int &r2 = r + i;

同样的初始化对于非const引用是不合法的,而且会导致编译时错误。
将引用绑定到不同的类型
double dVal = 3.14;
const int &ri = dVal;
编译器会将这些代码转换为一下形式:
int temp = dVal;
const int &ri = temp; //编译器会创建一个int型的暂时变量存储dVal,然后将ri绑定到temp上
注意:引用在内部存放的是一个对象的地址,它是该对象的别名,对于不可寻址的值,如文字常量,以及不同类型的
对象,编译器为了实现引用,必须生成一个临时对象,引用实际上指向该对象,但用户不能访问它。
如果ri不是const,那么可以给ri赋一新值。这样做不会修改dVal的值,而是修改了temp,所以需要使用const引用
表示该变量时只读的。
注意:非const引用只能绑定到与该引用相同类型的对象。
const引用则可以绑定到不同相关的类型的对象或绑定到右值。

1.1.4 const对象的动态数组
如果我们在自由存储区中创建了数组存储内置类型的const对象,则必须为这个数组提供初始化,因为数组元素
都是const对象,无法赋值,实现这个要求的唯一方法是对数组做值初始化。
//Error
const int *pci_bad = new const int[100];
//Ok
const int *pci_ok = new const int[100]();
C++允许定义类型的const数组,但该类型必须提供默认构造函数:
const string *pcs = new string[100]; //这里便会调用string类型的默认构造函数初始化数组元素
1.1.5 指针和const限定符的关系
const限定符和指针结合起来常见的情况有:
(1)指向常量的指针【指向const对象的指针】
C++为了保证不允许使用指针改变所指的const值这个特性,强制要求这个指针也必须具备const特性:
const double *cptr;
这里cptr是一个指向double类型const对象的指针,const先顶了cptr指向的对象的类型,而并非cptr本身,所以cptr
本身并不是const。所以定义的时候并不需要对它进行初始化,如果需要的话,允许给cptr重新赋值,让其指向另一个
const对象。但不能通过cptr修改其所指对象的值。
*cptr = 42; //error
而我们将一个const对象的地址赋给一个普通的非const指针也会导致编译错误。
const double pi = 3.14;
double *ptr = π     //Error
const double *cptr = π  //Ok
不能使用void*指针保存const对象的地址,必须使用const void*类型的指针保存const对象的地址。
const int universe = 42;
const void *cpv = &universe;  //ok
void *pv = &universe; //Error universe是const的
允许把非const对象的地址赋给指向const对象的指针
double dval = 3.14;
cptr =  &dval;
不能通过cptr指针来修改dval的值,即使它指向的是非const对象。
不能使用指向const对象的指针修改基础对象,然而如果该指针指向非const对象,可用其他方式修改所指向的对象,
所以实际上,可以修改const指针所指向的值,但是不能通过const对象指针来进行而已。
dval = 3.1415926; //一个非const对象
*cptr = 3.1555;   //Error!!! cptr是指向const对象的,不能进行赋值
double *ptr = &dval;  //定义一个非const指针指向dval
*ptr = 2.155;      //将dval的值修改,此时*cptr的值就发生了改变

(2)常指针(const指针)
C++中还提供了const指针----本身的值不能被修改。
int errNumb = 0;
int *const curErr = &errNumb; //curErr是一个const指针
这是指向int型对象的const指针,与其他const量一样,const的值不能被修改,这意味着不能使curErr指向其他对象,
Const指针也必须在定义的时候初始化。
curErr = curErr; //错误,即使是赋值给相同的值

(3)指向常量的常指针(指向const对象的const指针)
const double pi = 3.1415926;
const double *const pi_ptr = π

1.2 函数和const限定符的关系
1.2.1 类中的const成员函数(常量成员函数)
在一个类中,任何一个不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数式,不慎修改了
数据成员,或者调用了非const成员函数,编译器将指出错误,提高了函数的健壮性。使用const修饰的函数叫做常成
员函数,只有常成员函数才有资格操作常量和常对象。
class Stack
{
private:
int m_num;
int m_data[100];
public:
void Push(int elem);
int Pop(void);

int GetCount(void) const;  //定义const成员函数
};


int Stack::GetCount(void) const
{
++m_num;  //编译错误,企图修改成员变量m_num
Pop();  //编译错误,企图修改被const成员函数
return m_num;


1、函数重载
const是定义为const函数的组成部分,那么可以通过添加const实现函数重载
class R
{
public:
R(int r1,int r2)
{
R1=r1;
R2=r2;
}
void print();
void print() const;
private:
int R1,R2;
};
void R::print()
{
cout<<R1;
}
void R::print() const
{
cout<<R2;
}
void main()
{
R a(5,4);
a.print();
const R b(20,52);
b.print();
}
print成员函数实现了两个版本,输出结果为5,52。const对象默认调用const成员区。

1、const修饰函数返回值
const修饰函数返回值的含义和const修饰普通变量以及指针的含义基本相同。
//这个其实无意义,因为参数返回本身就是赋值
const int fun1();
//调用const int *pValue = fun2();
//我们可以把fun2()看作成一个变量,即指针内容不可变
const int * fun2();
//调用时int * const pValue = fun2();
//我们可以把fun2()看做成一个变量,即指针本身不可变
int* const fun3();  
一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。
通常不建议用const修饰函数的返回值类型为某个对象或某个对象的引用的情况,如果这样
则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员
函数,并且不允许对其进行复制操作。
1、const修饰函数参数
1)传递过来的参数在函数内不可以(无意义,因为var本身就是形参)
void function(const int var);
2)参数指针所指内容为常量不可变
void function(const char* var);
3)参数指针所指内容为常量不可变
void function(const char* var);
4)参数为引用,为了增加效率同时防止修改。修饰引用参数
void function(const Class& var);//引用参数在函数内不可以改变
void function(const TYPE& var);//引用参数在函数内为常量不可变
const引用传递和普通的函数传递的效果是一样的,他禁止对引用对象的一切修改,唯一不
同的是按值传递会先建立一个类对象的副本,然后传递过去,而他直接传递地址,所以这种
传递比按值传递更有效。
5)const限定符和static的区别
1]const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行
后不会释放其存储空间。
2] static表示的是静态的。类的静态成员函数、静态成员变量时和类相关的,而不是和类具体的
对象相关的。即使没有具体对象,也能调用类的静态成员函数和成员变量。一般类的静态函数几乎
是一个全局变量,只不过他的作用域限于包含它的文件中。
3] 在C++中,static静态变量不能在类的内部初始化。在类的内部只是声明,定义必须咋类定义体
的外部,通常在类的实现文件中初始化。如:double Account::Rate=2.25; static关键字只能用于
类定义体内部的声明中,定义时不能标示为static
4] 在C++中,const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表,并且必须有构造
函数
5] const数据成员,只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建
多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,
因为类的对象没被创建时,编译器不知道const数据成员的值是什么。
6] const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的
常量,应该用类中的枚举常量来实现,或者static const。
class Test
{
public:
Test():a(0){}
enum {size1=100,size2=200};
private:
const int a;     //只能在构造函数的初始化列表初始化
static int b;  //在类的实现文件中定义并初始化
const static int c;   //与static const int c,相同
};
int Test::b=0;    //static成员变量不能在构造函数初始化列表中初始化,因为它不属于某个对象
const int Test::c=0;   //注意:给静态成员变量赋值时,不需要加static修饰符。但要加const

6)const成员函数主要目的是防止成员函数修改对象的内容。即const成员函数不能修改成员变量的值,

但可以访问成员变量。当方法成员函数时,该函数只能是const成员函数。
7)static成员函数主要目的是作为类作用域的全局函数。不能访问类的静态数据成员。类的静态成员
函数没有this指针,这导致:1、不能直接存取类的非静态成员变量,调用非静态成员函数 2、不能声
明为virtual。

2、关于static、const、static const、const static成员的初始化问题
1)类里的const成员初始化
class foo
{
public:
foo():i(100){}
private:
const int i=100; //error,不能在类中初始化
};
//
foo::foo():i(100)
{

}
2)类里的static成员初始化
类中的static变量时属于类的,不属于某个对象,它在整个程序的运行过程中只有一个副本,因此在定义
对象时,对变量进行初始化,就是不能使用构造函数进行初始化,正确的初始化方法是:
数据类型 类名::静态数据成员名=值
class foo
{
public:
foo();
private:
static int i;
};

int foo::i=20;
/*
这表明:
1、初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆
2、初始化时不加该成员的访问权限控制符private,public等
3、初始化时使用作用域运算符来表明它所属的类,因此,静态数据成员是类的成员而不是对象的成员
*/

3)类里的static const和const static成员初始化(这两种写法是一致的)
class Test
{
public:
static const int mask1;
const static int mask2;
};
const Test::mask1=0xffff;
const Test::mask2=0xffff;
//他们的初始化没有区别,一个是静态常量,一个是常量静态
//静态都将存储在全局变量区域,其实最后结果都一样
//可能在不同的编译器内,不同处理,但最后结果都一样


完整的例子
#include <iostream>
using namespace std;
class A
{
public:
A(int a);
static void print();//静态成员函数
private:
static int aa;//静态数据成员的声明
static const int count;//常量静态数据成员(可以在构造函数中初始化)
const int bb;//常量数据成员
};
int A::aa=0;   //静态成员的定义+初始化
const int A::count=25;  //静态常量成员定义+初始化
A::A(int a)::bb(a)
{
aa+=1;
}
void A::print()
{
cout<<"count="<<count<<endl;
cout<<"aa="<<aa<<endl;
}
void main()
{
A a(10);
A::print();    //通过类访问静态成员函数
a.print();    //通过对象访问静态成员函数
}

3、const的难点
如果函数需要传入一个指针,面试官可能会问是否需要为该指针加上const,把
const加在指针不同的位置有什么区别;如果写的函数需要传入的参数是一个复杂
类型的实例,面试官可能会问传入值参数或者引用参数有什么区别,什么时候为
传入的引用参数加上const.

const是用来声明一个常量的,当你不想让一个值被改变时就用const,const int max
和int const max是没有区别的,都可以。不涉及到指针const容易理解。
int b=100;
const int *a=&b;  //[1]
int const *a=&b;  //[2]
int* const a=&b;  //[3]
const int* const a=&b;  //[4]

如果const位于星号的左侧,则const就是用来修改指针所指向的变量,即指针指向的对象
为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),
这种情况下不允许对内容进行更改操作,如不能*a=3,[3]为指针本身是常量,而指针所指向的
内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的,[4]为指针本身和
指向的内容均为常量。
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 公公在我洗碗时在厨房要了我 大嫂被肉翻了天佐佐木明希1 教师蕾丝短裙中文字幕 瓜棚里和大嫂乱禽 强睡大嫂中文字 免费 佐佐木明希 房东中文字幕 与父亲干柴烈火 中文字幕丈夫不在 9大嫂被禽翻中文字幕 侵犯你的贞洁 中文字幕 年轻的妻子在线观中文字幕 大嫂被翻天了佐佐木b希中文7 美丽的大嫂中文字幕影迅雷下载 邻居的妻子中文字幕下载 神马电影院电影中文 神马电影院理论中文 女儿的朋友5中文神马电影院 97手机2019电影院专用版中文 厨房里进入朋友的老婆 中文版电影院 神马电影院 中文 儿子的妻子中文字幕 下载 樱桃中文版电影院 大富豪电影院韩国中文 老婆的闺蜜们喝醉了在家 中文潮人影院您手中的电影院 朋友不在晚上去他家干 趁兄弟喝醉上他女朋友在线播放 神马电影院午伦中文 朋友喝醉上其妻 我朋友的妻子韩语中文2018 在朋友家趁朋友喝醉上他老婆 日本朋友的妻子和母亲中文版 偷朋友的妻子在线中文播放 邻居的妻子日本中文2018 朋友的妻子日本中文版7 朋友的妈l妈中文字电影 母亲在美国被黑人证服 妻子报恩献身张局长加强版2 日本朋友的家教妻子中文字幕 妻陪领导睡全文阅读