上一节讲到mutable时,使用了const限定符,本节主要是对cv限定符进行说明。const在平常经常使用,它可以被施加于任何作用于内的对象、函数参数、函数返回类型、成员函数本体等。另外限定符中还有一种:volatile,它是为了改善编译器的优化能力而设的。
- const:表示一个被修饰的对象不能被修改。使用它可以使得编译器强制实施这项约束。他可以修饰类之外的global或者namespace作用域的常量,也可以修饰static对象或者变量。在使用const需要注意地方主要有:
1.#define与const的区别与使用
在effictive c++中条款2和3都提到尽量使用const,在#define与const都可使用的情况下,推荐使用const。至于原因,自己感觉不是很清楚,从网上查阅了不少资料,对两者的区别总结如下:
#define TEST_RADIO 1.653
const double TestRadio =1.653;
(1)#define是宏定义语句,由预处理器处理,对编译器是透明的;const则是c++的关键字,被修饰变量即为常量,是由编译器处理的。
(2)#define定义的TEST_RADIO没有类型,同样没有类型检查;const定义的TestRadio则声明为double类型,在编译阶段会检查其类型。
(3)#define定义的TEST_RADIO是一个立即数,没有内存分配,在使用过程中则是每次使用就需要分配一次内存;const定义的TestRadio则是一次分配,以后使用过程中只是传递其内存地址,并不增加内存。
(4)#define不重视作用域,无法创建class专属变量,没有封装性;const则使用较为灵活,可以修饰class专属变量、指针、函数等,作用域与其声明的位置不同而变化。
2.const初始化
const修饰的变量在不同地方声明,其初始化规则是不同的,尤其同static、extern结合使用的时候。具体初始化规则解释如下:
ConstTest.h
class ConstTest
{
public:
ConstTest();
~ConstTest();
public:
double test2; //只能在类内部初始化
const double test3 ; //必须在初始化列表中初始化,不能在构造函数初始化
const static int test4 =4; //只有静态整型常量可在声明时初始化或者在类外初始化,其他只能在类外初始化
static double test5; //必须在类外初始化
static const double test8; //同test4
};
#include "ConstTest.h"
double test0 = 0.01; //一般要求在声明时初始化,亦可以不用。可在其他文件中使用
const double test1 = 0.11; //必须在声明时初始化,默认链接性为内部(只能在本文件中使用)
extern const double test6 =0.66; //声明时必须初始化,不然无法使用。提供外部链接性(可在其他文件中使用)
static const double test7 = 0.77; //同test
const double ConstTest::test8 =0.88; //类专属静态常量,初始化在类外,不必再写static关键在,但是必须写const关键字
double ConstTest::test5 = 0.55; //类专属静态变量,初始化在类外
ConstTest::ConstTest():test3(0.33) //类专属常量,必须在成员初始化列表中初始化
{
test2 = 0.22; //类专属变量
}
ConstTest::~ConstTest()
{
}
#include <iostream>
#include "ConstTest.h"
extern double test0;
//extern double test1; //链接性为内部,无法使用
extern const double test6 ;
//extern double test7; //链接性为内部,无法使用
using namespace std;
int main()
{
ConstTest* test = new ConstTest;
cout<<"extern修饰的全局变量test0="<<test0<<"\n";
cout<<"test1是链接性为内部,且非类专属的常量,无法使用"<<"\n";
cout<<"普通类专属非静态变量test2="<<test->test2<<"\n";
cout<<"const修饰类专属非静态常量test3="<<test->test3<<"\n";
cout<<"const、static修饰类专属静态常量test4="<<test->test4<<"\n";
cout<<"static修饰类专属静态变量test5="<<test->test5<<"\n";
cout<<"extern、const修饰的全局常量test6="<<test6<<"\n";
cout<<"test7是链接性为内部,且非类专属的静态常量,无法使用"<<"\n";
cout<<"static、const修饰类专属静态常量test8="<<test->test8<<"\n";
system("pause");
return 0;
}
以上的运行结果是:
3.const修饰指针,const在不同的位置是有不同的意义的。
int m_test = 1;
int* p = &m_test; //指针和指针指向的值都不是常量
const int* p = &m_test; //指针不是常量,可更改指向,指针指向的值是常量,不可以通过指针操作符修改
int* const p = &m_test; //指针是常量,不可以更改指向与加减,其指向的值不是常量,可以通过指针操作符修改
const int* const p = &m_test; //指针与指针指向的值都是常量,都不可修改
注意:将const放在类型之后,星号*之前 和 const放在类型之前的的意义是一致的。
4. const修饰函数的返回值,尤其是一些重载操作符的函数;修饰函数形参;修饰类成员函数本身。
class Test{
...
const Test operator* (const Test& lhs, const Test& rhs); //修饰函数的形参,可以使得形参在函数中被修改。
void Show() const; //修饰成员函数,防止该成员函数修改调用的对象
};
Test a,b,c;
...
(a*b) = c; //可防止对函数的返回值进行在再赋值