C++ - const

以下内容参考自《程序员面试宝典》

 

(一)指针常量 & 常量指针

关于const修饰指针的情况,可以分为以下4种情况:

int b = 1;
const int* a = &b;        // case 1
int const *a = &b;        // case 2
int* const a = &b;        // case 3
const int* const a = &b;  // case 4

如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量(指针常量),e.g. case 1和case 2;如果const位于星号的右侧,则const就是修饰指针本身,即指针本身是常量(常量指针),e.g. case 3。

对于指针常量,我们不允许对指针指向地址的内容进行更改。e.g.

int b = 1;
const int* a = &b;
*a = 0;    // error

但是可以通过其他方式来修改*a的值:

(1)通过改变b的值:

int b = 1;
const int* a = &b;
b = 0;
cout << *a << endl;    // 0

(2)使a指向另一处地址:

int b = 1;
const int* a = &b;
int c = 0;
a = &c;
cout << *a << endl;    // 0

对于指针常量,可以先不进行初始化。因为虽然指针内容是常量,但是指针本身不是常量。e.g.

const int* a;    // 编译通过

对于常量指针,我们不能使指针指向另一处地址,因为指针本身是一个常量,也正因如此,在定义时就需要初始化。e.g.

int b = 1;
int* const a;    // error,需要初始化
int* const a = &b;
*a = 0;    // 编译通过,允许对指向地址的值就行修改
cout << a++ << endl;    // error,不允许对指向的地址进行修改

对于case 4,则是严格要求指针和指针指向地址的值都是常量,那么就是只能作为右值了。

 

(二)const成员函数

为了使成员函数的意义更加清楚,我们可以在不改变对象的成员函数的函数原型中加上const。e.g.

class A{
    private:
        int a;
    public:
        int getA() const;
};

// 关键字const必须在函数声明与函数实现中保持一致,否则编译器会把它们看成不同的函数
int A::getA() const{
    return a;
}

如果const成员函数中试图修改成员变量或者调用另一个非const成员函数,编译器将会报错(cannot assign to non-static data member within const member function 'getA')。但是对于静态变量(不过要注意静态变量一定要初始化)或者是带有mutable关键字修饰的成员变量,则是可以编译通过的。e.g.

class A{
    private:
        int a;
		static int b;
		mutable int c;

	public:
        int getA() const;
};

int A::b = 0;

// 关键字const必须在函数声明与函数实现中保持一致,否则编译器会把它们看成不同的函数
int A::getA() const{
	b++;
	c--;
	return a;
}

如果把const放在函数声明的前面,那么就意味着函数的返回值是常量,意义就完全不同了。

 

(三)const & #define

C++可以用const定义常量,也可以用#define定义常量,但是前者比后者有更多的优点:

  • const常量有数据类型,而宏定义常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应——由于边缘运算符优先级较高而先对边缘进行运算)。
  • 有些集成化的调试工具可以对const常量进行调试,但是不能对宏定义常量进行调试。

你可能感兴趣的:(note)