C++ - const 关键字
const 变量一经赋值,不能修改
若在源代码中,const变量被修改,则编译器会报错 'l-value specifies const object'
(一) 常量指针 vs 指针常量 【面试题2-7】
1 #include <stdio.h> 2 3 int main() 4 { 5 const int x = 1; 6 int b = 10; 7 int c = 20; 8 9 const int* a1 = &b; 10 int* const a2 = &b; 11 const int* const a3 = &b; 12 13 x = 2; // wrong! Line 5 const int x =1 赋值 不能修改 14 15 a1 = &c; // Right. Line 9 中 const 修饰的是 *a1, *a1为 int 类型,a1本身可以修改 16 *a1 = 1; // wrong! *a1 是 const, 不能修改,报错 l-value specifies const object 17 18 a2 = &c; // wrong! Line 10 中 const 修饰 a2, a2 是 const, 不能修改 19 *a2 = 1; // right. *a2 是 int 类型,可以修改 20 21 a3 = &c; // wrong! Line 11 中 a3 和 *a3 均为 const, 不能修改。 22 *a3 = 1; // wrong! Line 11 中 a3 和 *a3 均为 const, 不能修改 23 24 return 0; 25 }
(二)说明 #define 与 const 的特点及区别 【面试题2-8】
(2.1) #define
1 #define PI 3.1415926 2 float angel; 3 angel = 30 * PI / 180;
#define:程序在预编译期间,会将所有 PI 替换成 ‘3.1415926’, 然后进行编译.
#define 常量是一个 "Compile-Time" 概念, 因此它存在与程序的代码段,在实际运行中它没有实在意义
(2.2) const
const 变量存在于程序的数据段,并在推展分配了空间。
const常量是一个‘Run-time’的概念。它在程序中确确实实地存在着并可以被调用,传递。
const 有数据类型,#define 没有数据类型。
编译器可以对const 常量进行类型安全检查。
(三)C++ 中 const 有什么作用? 【面试题2-9】
(1)const 用于定义常量;const 定义的常量,编译器可以对其进行数据静态类型安全检查
(2) const 修饰函数形式参数:当输入参数为用户自定义类型和抽象数据类型时,应该将 ‘值传递’ 改为 'const & 址传递', 可以提高效率。
1 void fun(A a); 2 void fun(A const &a);
以上代码,Line 2 的执行效率比 Line 1 高,因为‘引用传递’不需要产生临时变量,没有构造,复制,析构的过程。但光引用 A& a 有可能改变 a, 因此加上 const
(3)const 修饰函数的返回值,则返回值不能被修改,同时要求返回值只能赋值给 const 修饰的同类型变量
1 #include <stdio.h> 2 const int fun() {return 1;} 3 int main(){ 4 const int m = fun(); // 用 const 变量 接收 返回值 为 const 的函数 的 返回 5 return 0; 6 }
(4)const 修饰类的成员函数:任何不会修改数据成员的函数都应用 const 修饰,这样,当不小心修改了数据成员或调用了非 const 成员函数时,编译器都会报错。const 修饰类的成员函数形式为
int GetCount(...) const;
【注意】以上表达与 const int GetCount(...) 不同,const int GetCount(...) 表示返回值是 int 类型的常数
【例子】
1 class Student{ 2 public: 3 Student(char* name, int age, float score); 4 void show(); 5 char* getname() const; 6 int getage() const; 7 float getscore() const; 8 private: 9 char *m_name; 10 int m_age; 11 float m_score; 12 }; 13 14 Student::Student(char* name, int age, float score):m_name(name),m_age(age),m_score(score){} 15 void Student::show(){ 16 cout<<m_name<<"'s age is "<<m_age<<" with score of "<<m_score<<endl; 17 } 18 char* Student::getname() const {return m_name;} 19 int Student::getage() const {return m_age;} 20 float Student::getscore() const {return m_score;}
【注意】类中的const成员函数的定义和实现都需要同时在函数头部的结尾加上 const 关键字。char* getname() const 与 char* getname() 是两个不同的函数原型,若只在一个地方加 const 会导致生命和定义处的函数原型冲突。
(5)初始化 const 成员变量的 唯一方法是使用初始化列表
1 class VLA{ // 正确的版本 2 private: 3 const int m_len; 4 int *m_arr; 5 public: 6 VLA(int len); 7 }; 8 //必须使用初始化列表来初始化 m_len 9 VLA::VLA(int len):m_len(len){ 10 m_array = new int[len]; 11 }
class VLA{ // 错误的版本 private: const int m_len; int *m_arr; public: VLA(int len); }; VLA::VLA(int len){ m_len = len; // const int m_len 不能在这里被初始化 m_arr = new int[len]; }
参考 (Reference)
[1] C 和 C++ 程序员面试秘诀-精选最常见的C/C++面试真题: 董山海
[2] http://c.biancheng.net/view/2230.html
[3] http://c.biancheng.net/view/2223.html