1. const 在C和C++中的区别
(1)在C中,const变量是一个“不能被改变的普通变量”,既然是变量,就要占用存储空间,所以编译器不知道编译时的值,所以在C中可以这么写:
const int size; //被看做一个声明,它会在别的地方分配存储空间
但不能这么写:
const int size=100;
char buf[size]; //因为size不是常量
但在C++中,const被看成编译期的常量,编译器并不为const分配空间,但必须在初始化时赋值,并且可以作为数组的维数。因此,可以这么写:
const int size=100;
char buf[size]; //因为size是常量
(2)C++中const默认是内部连接,而C中使用外部连接.C++中要想使用外部变量,必须用extern声明(注意:声明应用的变量不能是const)
内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.
外连接:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过extern关键字声明,可以从其他文件访问相应的变量和函数.C++中,是否为const分配空间要看具体情况. 如果加上关键字extern或者取const变量地址,则编译器就要为const分配存储空间.
如:
a.cpp中:
const int a=10;
b.cpp中:
const int a=20;
cout<<a<<endl;
则编译正确,输出结果为20
但如果改为:
a.cpp中:
int a=10;
b.cpp中:
int a=20;
cout<<a<<endl;
则显示 fatal error LNK1169: 找到一个或多个多重定义的符号再比如:
a.cpp中:
const int a=10;
b.cpp中:
extern const int a;
cout<<a<<endl;
则会编译出错:无法解析的外部符号 "int const a"
但改为
a.cpp中:
extern const int a=10;
b.cpp中:
extern const int a;
cout<<a<<endl;
则正确,C++中const变量默认只能在本文件中可见,但是如果加上extern则可以抑制const的这种特性
C++中定义常量的时候不再采用define,因为define只做简单的宏替换,并不提供类型检查.
2.const指针和指向const的指针
在C语言中const指针表示该指针是一个常量,一旦进行初始化完成之后就无法改变它指向的位置。指向const的指针说明使用这个指针无法改变其指向的地址处的值,特别强调的一点是使用这个指针不能够改变。言外之意就是说,可以通过其他的方式改变。
比如:char ch='c';
const char *ptr=&ch;
*ptr='a';//这样做是不允许的
ch='a';//这样做完全可以,并且*ptr的值也是'a'
const int* a = & [1] //非常量数据的常量指针 指针常量int const *a = & [2] //非常量数据的常量指针 a is a pointer to the constant char variable
int* const a = & [3] //常量数据的非常量指针指针常量 常量指针 a is a constant pointer to the (non-constant) char variable
const int* const a = & [4] //常量数据的常量指针
如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
因此,[1]和[2]的情况相同,都是指针所指向的内容为常量,这种情况下不允许对内容进行更改操作,如不能*a = 3 ;
[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;
[4]为指针本身和指向的内容均为常量。
3.const修饰引用
int const &a=x;
const int &a=x;
int &const a=x;//这种方式定义是C、C++编译器未定义,虽然不会报错,但是该句效果和int &a一样。
//这两种定义方式是等价的,此时的引用a不能被更新。如:a++ 这是错误的。
4.const应用到函数中
(1)修饰参数的const
如 void fun0(const A* a ); void fun1(const A& a);
调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,
则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;
如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
[注意]:参数const通常用于参数为指针或引用的情况;
(2)修饰返回值的const
如const A fun2( ); const A* fun3( );
这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
返回值用const修饰可以防止允许这样的操作发生:
Rational a,b;
Radional c;
(a*b) = c;
一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。
类中的成员函数:A fun4() const; 其意义上是不能修改所在类的的任何变量。
5. 类中定义常量
(1)使用枚举类型
class test
{
enum { SIZE1 = 10, SIZE2 = 20}; // 枚举常量
int array1[SIZE1];
int array2[SIZE2];
};
(2)使用const
不能在类声明中初始化const数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道SIZE的值是什么。
class test
{
const int SIZE = 100; // 错误,企图在类声明中初始化const数据成员
int array[SIZE]; // 错误,未知的SIZE
};
只有静态常量整型数据成员才可以在类中初始化
class test
{
static const int SIZE = 100; // 正确
int array[SIZE]; // 正确
};
但是静态变量必须在类外定义
class test
{
public:
static int SIZE = 100; // 错误,只有静态常量整型数据成员才可以在类中初始化
};
正确的使用const实现方法为:const数据成员的初始化只能在类构造函数的初始化表中进行。
class A
{…
A(int size); // 构造函数
const int SIZE ;
};
A::A(int size) : SIZE(size) // 构造函数的初始化表
{
…
}
//error 赋值的方式是不行的
A::A(int size)
{
SIZE=size;
}
void main()
{
A a(100); // 对象 a 的SIZE值为100
A b(200); // 对象 b 的SIZE值为200
}
注意:对const成员变量的初始化,不能在变量声明的地方,必须在类的构造函数的初始化列表中完成,即使是在构造函数内部赋值也是不行的。
当const放在类成员函数的后面:
class test
{
public:
void f( int a) const {};
}
表示这是一个常成员函数。常成员函数可以理解为是一个“只读”函数,它既不能更改数据成员的值,也不能调用那些能引起数据成员值变化的成员函数,只能调用const成员函数。
#include<iostream>
using namespace std;
class A{
int data;
public:
A(int da=100):data(da){}
void display1(){cout<<data<<endl;}
void display2() const {cout<<data<<endl;}
void display3() const
{
data+=100;
cout<<data<<endl;
}
};
int main()
{
A a1;
const A a2;
a1.display1();
a1.display2();
a1.dispaly3(); //error ,const声明的成员函数不能改变数据成员的值
a2.display1(); //error ,const对象不能调用非const函数
a2.display2(); //right
a2.display3(); //error ,const对象不能调用非const函数,且不能改变数据成员值
return 0;
}
const修饰成员函数总结
(1) const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.(2)const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
(3)const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
(4)然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的