C++ const总结

  • 记录const的使用特点,参考自C++ primer plus 附录


1、使用const 而不是 #define 来定义常量

  • 在C/C++中定义常量通常使用const关键字,当然你也可以使有宏#define来定义。
  • 这两种方式定义常量如下所示:
// const 定义常量
const int PI = 3.14;

// 宏定义常量
#define PI = 3.14
  • 首先介绍一下#define是如何工作的:
  • 编译器在编译我们写好C/C++程序时,其编译器过程为:预编译->编译->链接。
  • #define的替换就是在预编译阶段完成的,也就是说在预编译阶段将C++中的所有用到的宏都用宏定义中的值替换掉。
  • 说说使用const的优越性
  • <1>. const显式的指明了类型,而使用#define必须加后缀指出类型,如使用 100L 来表示long类型。
  • <2>. const方法可以很方便的用于复合类型,如:
const int base_vals[3] = {
    
    10,20,30};
const string ans[3] = {
    
    "yes", "no", "maybe"};
  • <3>. const标识符遵循变量的作用域,因此,可以创建作用域为全局、名称空间、数据块的常量,在特定情况下,不必担心定义会与程序的其他地方使用的全局变量冲突。

例如:

#define n 5
const int dz = 12;
...
void fizzle() {
    
     
	int n;
	int dz;
	...
}
  • 预处理器把 int n;替换为 int 5;, 导致编译出错。
  • fizzle()中定义的dz是本地变量,必要时可以通过作用域解析运算符(::),以::dz的方式访问该常量。

所以,对于符号常量,习惯上还是使用const,而不是#define


2、const 与 变量的链接性

  • C语言一样,C++也为静态持续变量提供了三种链接性:
  • <1>. 外部链接性(可在其他文件中使用)
  • <2>. 内部链接性(可在当前文件中访问)
  • <3>. 无链接性 (可在当前代码块中访问)
    C++primer plus 308
  • 在默认情况下全局变量的链接性为外部,但是const全局变量的链接性为内部,也就是说,在C++看来,全局const定义就像使用了static说明符一样:
const int fingers = 10;
// same as
static const int fingers = 10;
  • 重点1:内部链接性意味着每一个文件都有属于自己的一组常量,这也是可以将常量定义放在头文件的原因。
       只要在两个源代码文件中包括同一个头文件,则他们可使用同一组常量。
  • 重点2:使用 extern 可以覆盖变量默认的内部链接性,使其具有外部链接性,如:
           extern const int states = 50;
        并在所有使用该常量的文件中使用extern来声明它。
  • 重点3:``重点2与定义常规外部变量不同之处:定义常规外部变量时,不必使用extern关键字,但在使用时必须使用extern

3、const 与 变量

  • 常变量: const + 类型说明符 + 变量名
  • 常引用: const + 类型说明符 + &引用名
  • 常对象: 类名 + const + 对象名
  • 常数组: 类型说明符 + const + 数组名[大小]
  • 常成员函数: 类名::fun(形参) + const
  • 常指针: const + 类型说明符* + 指针名 ,类型说明符* + const + 指针名

3.1 int const 和 const int 的区别

  • 首先提示的是在 常变量常引用常对象常数组中,const 与 “类型说明符”或“类名”的位置可以互换。指针特殊考虑。
 // type const name 与 const type name  含义相同
 
 // 普通类型
 const int a=5;
 int const a=5; 				// 二者相同

// &
int const &bb = num;
const int& bb = num;			// 二者相同

// 对于指针, 此处 *pt看为 name
int age = 10;
const int *pt = &age;    		// *pt 的值为 const,不能被修改
int const *pt = &age;	 		// 二者相同

3.2 Const 与 指针

  • const用于指针的方式,可以分为两种不同方法:
  • <1>. 让指针指向一个常量对象,这样可以防止使用改指针修改所指向的值。可以将非指const针赋给const指针
// <1>. 让指针指向一个常量对象
int age = 10;
const int *pt = &age;    	// 对 pt而言,age 的值为 const,不能被修改
							// 可以通过age来修改age的值,不可以用 pt指针修改它

// 该方法可以防止pt修改指向的值, 但可以将一个新地址赋给 pt
int age = 20;
pt = &age; 					// 此时,仍然不能使用pt修改指向的值
  • <2>. 将指针本身声明为常量,这样可以防止改变指指针向的位置。
// <2>. 将指针本身声明为常量
int sloth = 3;
const int * ps = &sloth;
int * const fig = &sloth; 	// 该声明使fig 只能指向sloth, 但允许使用fig 来修改sloth 的值。

4、const 与 函数

  • const修饰函数参数可参考第三节。
  • 此处总结const修饰函数体const修饰函数返回值

4.1 const修饰函数体

  • const修饰类成员函数,称作const成员函数。规则如下:
  • <1>. const对象只能访问const成员函数,非const对象可以访问任意的成员函数(包括const成员函数)。
  • <2>. const成员函数不可以修改对象的数据,(在编译时,以是否修改成员数据为依据,进行检查)。
      此外, const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的。
#include <iostream>
using namespace std;

class Point{
    
    
public :
    Point(int _x):x(_x){
    
    }

    void testConstFunction(int _x) const {
    
    

        // 错误-1
        // 在const成员函数中,不能修改任何类成员变量:x;
        x=_x;

        // 错误-2
        // const成员函数不能调用 非const成员函数:modify_x(_x);
        // 因为 非const成员函数 可能会修改成员变量:x
        modify_x(_x);
    }

    void modify_x(int _x){
    
    
        x=_x;
    }
    int x;
};

4.2 const修饰函数返回值

  • 返回指向const对象的引用:
  • <1>. 返回对象将调用复制函数,返回引用则不会。
  • <2>. 引用指向的对象应该在调用函数期间存在(该对象不是函数中新建的临时变量)。
  • <3>. 返回类型为const引用时,接收也应该使用const引用
Point Point_A(1);
Point Point_A(2);

// 返回 const对象的引用
const Point& max(const Point& one, const Point& two){
    
    
	// ...
	return one;
}
  • 要点总结
  • <1>. 如果函数返回的是局部对象(临时变量),则应该返回对象(复制构造函数),而不是返回对象的引用。
  • <2>. 如果函数返回的对象(该类无复制构造函数),返回一个指向对象的引用。
  • <3>. 返回引用效率更高。

猜你喜欢

转载自blog.csdn.net/u013271656/article/details/110648088