C++总结:C++中的const和constexpr(转)
2014-03-25 17:13
477 查看
C++总结:C++中的const和constexpr
C++中的const可用于修饰变量、函数,且在不同的地方有着不同的含义,现总结如下。const的语义
C++中的const的目的是通过编译器来保证对象的常量性,强制编译器将所有可能违背const对象的常量性的操作都视为error。对象的常量性可以分为两种:物理常量性(即每个bit都不可改变)和逻辑常量性(即对象的表现保持不变)。C++中采用的是物理常量性,例如下面的例子:
1 2 3 4 5 6 7 | struct A { int *ptr; }; int k = 5, r = 6; const A a = {&k}; a.ptr = &r; *a.ptr = 7; |
逻辑常量性的另一个特点是,const对象中可以有某些用户不可见的域,改变它们不会违背逻辑常量性。Effective C++中的例子是:
1 2 3 4 5 6 7 8 9 | class CTextBlock { public : ... std:: size_t length() const ; private : char *pText; std:: size_t textLength; bool lengthIsValid; }; |
本部分总结:C++中const的语义是保证物理常量性,但通过mutable关键字可以支持一部分的逻辑常量性。
const修饰变量
如上节所述,用const修饰变量的语义是要求编译器去阻止所有对该变量的赋值行为。因此,必须在const变量初始化时就提供给它初值:1 2 3 | const int i; i = 5; const int j = 10; |
1 2 3 4 | const int COMPILE_CONST = 10; const int RunTimeConst = cin.get(); int a1[COMPLIE_CONST]; int a2[RunTimeConst]; |
文件域的const变量默认是文件内可见的,如果需要在b.cpp中使用a.cpp中的const变量M,需要在M的初始化处增加extern:
1 2 3 4 5 | extern const int M = 20; extern const int M; |
const修饰指针与引用
const修饰引用时,其意义与修饰变量相同。但const在修饰指针时,规则就有些复杂了。简单的说,可以将指针变量的类型按变量名左边最近的‘*’分成两部分,右边的部分表示指针变量自己的性质,而左边的部分则表示它指向元素的性质:
const指针的解读规则差不多就是这些了……
指针自身为const表示不可对该指针进行赋值,而指向物为const则表示不可对其指向进行赋值。因此可以将引用看成是一个自身为const的指针,而const引用则是const Type * const指针。
指向为const的指针是不可以赋值给指向为非const的指针,const引用也不可以赋值给非const引用,但反过来就没有问题了,这也是为了保证const语义不被破坏。
可以用const_cast来去掉某个指针或引用的const性质,或者用static_cast来为某个非const指针或引用加上const性质:
1 2 3 4 | int i; const int *cp = &i; int *p = const_cast < int *>(cp); const int *cp2 = static_cast < const int *>(p); |
类中的const成员变量
类中的const成员变量可分为两种:非static常量和static常量。非static常量:
类中的非static常量必须在构造函数的初始化列表中进行初始化,因为类中的非static成员是在进入构造函数的函数体之前就要构造完成的,而const常量在构造时就必须初始化,构造后的赋值会被编译器阻止。1 2 3 4 5 6 7 8 | class B { public : B(): name( "aaa" ) { name = "bbb" ; } private : const std::string name; }; |
static常量:
static常量是在类中直接声明的,但要在类外进行唯一的定义和初始值,常用的方法是在对应的.cpp中包含类的static常量的定义:1 2 3 4 5 6 7 8 | class A { ... static const std::string name; }; const std::string A::name( "aaa" ); |
1 2 3 4 5 6 7 8 | class A { ... static const int SIZE = 50; }; const int A::SIZE = 50; |
const修饰函数
C++中可以用const去修饰一个类的非static成员函数,其语义是保证该函数所对应的对象本身的const性。在const成员函数中,所有可能违背this指针const性(const成员函数中的this指针是一个双const指针)的操作都会被阻止,如对其它成员变量的赋值以及调用它们的非const方法、调用对象本身的非const方法。但对一个声明为mutable的成员变量所做的任何操作都不会被阻止。这里保证了一定的逻辑常量性。另外,const修饰函数时还会参与到函数的重载中,即通过const对象、const指针或引用调用方法时,优先调用const方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class A { public : int &operator[]( int i){ ++cachedReadCount; return data[i]; } const int &operator[]( int i) const { ++size; --size; ++cachedReadCount; return data[i]; } private : int size; mutable cachedReadCount; std::vector< int > data; }; A &a = ...; const A &ca = ...; int i = a[0]; int j = ca[0]; a[0] = 2; ca[0] = 2; |
1 2 3 | int &A::operator[]( int i){ return const_cast < int &>( static_cast < const A &>(* this ).operator[](i)); } |
constexpr
constexpr是C++11中新增的关键字,其语义是“常量表达式”,也就是在编译期可求值的表达式。最基础的常量表达式就是字面值或全局变量/函数的地址或sizeof等关键字返回的结果,而其它常量表达式都是由基础表达式通过各种确定的运算得到的。constexpr值可用于enum、switch、数组长度等场合。constexpr所修饰的变量一定是编译期可求值的,所修饰的函数在其所有参数都是constexpr时,一定会返回constexpr。
1 2 3 4 5 6 7 | constexpr int Inc( int i){ return i + 1; } constexpr int a = Inc(1); constexpr int b = Inc(cin.get()); constexpr int c = a * 2 + 1; |
1 2 3 4 5 6 7 | struct A { constexpr A( int xx, int yy): x(xx), y(yy) {} int x, y; }; constexpr A a(1, 2); enum {SIZE_X = a.x, SIZE_Y = a.y}; |
是一种很强的约束,更好地保证程序的正确语义不被破坏。
编译器可以在编译期对constexpr的代码进行非常大的优化,比如将用到的constexpr表达式都直接替换成最终结果等。
相比宏来说,没有额外的开销,但更安全可靠。
原文链接:http://www.cnblogs.com/fuzhe1989/p/3554345.html
相关文章推荐
- C++总结:C++中的const和constexpr
- 关于C++ const 的全面总结 .
- C++_关于const 的全面总结
- C++中const用法总结
- C++中const关键词总结
- C++ const 的全面总结
- C++中const用法总结
- 关于C++ const 的全面总结
- C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结
- c++中对const的总结
- C++const用法总结
- 关于C++ const 的全面总结
- C++中const用法总结
- [c++学习]const用法总结篇
- 【C++学习】const的全面总结
- 关于C++ const 的全面总结
- c/c++中const用法总结
- C++中const总结
- C++_关于const 的全面总结
- C++中const用法总结