C++ const的一切

const限定符

如果你想定义一个不想被改变的变量,只需要在变量类型前面添加const限定符即可

初始化和const

如:

const int bufSize = 512;

因为const对象一旦创建之后就不能修改,所以const对象必须初始化。

const int j = get_size();       // 运行时初始化
const int j = 42;
int m = 88;
const int i = m;                // 可利用非const对象初始化const对象
const int k;                    // 错误:未经初始化的常量

如果是类或者结构体中的const对象,则必须在其构造函数初始化列表中进行初始化操作。

class const_class{
public:
    const_class():_data(20){}
private:
    const int _data;
}
默认状态下,const对象仅在文件内有效
// test1.h
const int bufsize = 512;

// test2.h
#include <iostream>
#include "test1.h"
const int bufsize = 256;

int main()
{
    std::cout << bufsize << std::endl; // print: 256
}


/**
各自的bufsize仅仅在各自的文件中有效,它们为单独的变量
*/

// 如果将test2.h去掉定义如下:
// test2.h
#include <iostream>
#include "test1.h"

int main()
{
    std::cout << bufsize << std::endl; // print: 256
}

// error: 'bufsize' was not declared in this scope

如果想在多个文件中共享某个const对象,则需要添加extern关键字:

// test1.cc
// 在源文件中进行定义
extern int bufsize = 512;
// test1.cc
#include<iostream>

// 必须要进行声明
extern int bufsize;

int main()
{
    std::cout << bufsize << std::endl; // print:512
}

const的引用

可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用(reference to const),与普通引用不一样,对常量的引用不能更改其引用的对象。
常量引用是对const的引用:严格说,并不存在常量引用。因为引用不使一个对象,没法使引用本身恒定不变。而C++语言本身不允许更改引用所绑定的对象

初始化对const的引用

引用类型必须与其所引用对象的类型一致

例外一
初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可
int i = 42;
const int &r1 = i;  // 允许将const int&绑定到一个普通的int对象上
int &r2 = r1 * 2;   // 错误,r2是一个非常量引用

double  dval = 3.14;
const int &ri = dval;
/**
因为dval可以转换为int类型,所以上式成立
编译器会产生一个临时量
*/
const int temp = dval;
const int &ri = temp;

指针与const

指向常量的指针

不能用于改变其所指对象的值。

const double pi = 3.14;
double *ptr = &pi;              // 错误:ptr是一个非常量指针
const double *cptr = &pi;
*cptr = 42;                     // 错误:不能修改指针常量

跟引用一样,允许一个指向常量的指针指向一个非常量对象。

double dval = 3.14;
cptr = &dval;
const 指针

指针是对象,而引用不是,因此可以像其他对象类型一样,允许把指针本身定为常量。常量指针(const point)必须初始化,且一旦初始化,其指向的地址不能更改

int errNumb = 0;
int *const curErr = &errNumb; // curErr将一直指向errNumb;
*curErr = 1;                  // 可以改变其指向的值

面对一个比较复杂的指针或引用的声明语句时,从右向左阅读有助于弄清楚它的真实含义

顶层const 与底层const

顶层const:表示指针本身时一个常量
底层const:表示指针所指的对象是一个常量

constexpr和常量表达式

常量表达式(const expression)是指不会改变且编译剁成就能得到计算结果的表达式。

const int max_files = 20;           // 常量表达式
const int limit = max_files + 1;    // 常量表达式
const int sz = get_size();          // 非常量表达式,因为其值需要运行时才确定
constexpr变量

在一个复杂的系统中,很难确定一个初始值是否为常量表达式。如上式中,就存在非常量表达式。
C++11新标准规定,允许变量声明为constexpr类型以便由编译器确定变量的值是否为一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须是常量表达式初始化。

constexpr int mf = 20;          // 常量表达式
constexpr int limit = mf + 1;   // 常量表达式
const int sz = size();          // 错误:非常量表达式
constexpr函数

constexpr函数(constexpr function)是指能用于常量表达式的函数
约定:函数的返回值及所有形参的类型都得是字面值类型,而且函数中必须有且只有一条return语句
constexpr函数不一定返回常量表达式

const int new_sz(int n)
{
    return n * 512;
} 
const int foo = new_sz(5);          // 常量表达式
int stuff = new_sz(10);             // 非常量表达式

把内联函数和constexpr函数放在头文件内
内联函数和constexpr函数可以在程序中多次定义。编译器想要展开函数仅有声明是不够得,必须要定义。对于给定得内联函数和constexpr函数,它们的多个定义必须一致。基于这个原因,所以需要放在头文件中。

字面值类型

常量表达式需要在编译阶段就能得到计算,因此对声明constexpr的变量必须有所限制,这些类型一般比较简单,值也显而易见,容易得到,则称之为“字面值类型”
目前字面值类型有:算术类型、引用和指针都属于字面值类型,自定义非constexpr类或结构体不属于字面值类型,也就不能定义为constexpr类型。

指针与constexpr

必须明确一点,在constexpr声明中如果定义了一个指针,限定符constexpr仅仅对指针有效,与指针所指之物无关

const int *p = nullptr;         // p是一个指向常量的指针
constexpr int *q = nullptr;     // q是一个指向整数的常量指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值