本文转载自微信公众号「码砖杂役」,作者我不想种地 。转载本文请联系码砖杂役公众号。
成都创新互联公司是一家专注于做网站、成都网站制作与策划设计,温州网站建设哪家好?成都创新互联公司做网站,专注于网站建设十载,网设计领域的专业建站公司;建站业务涵盖:温州等地区。温州做网站价格咨询:13518219792
很多人搞不清const、const_cast、constexpr的用法,稀里糊涂地用。一般而言,即使乱用,问题也不大,因为错大发了会崩,崩了自然会被修正,不崩自然也就没事。但作为一个有追求的专业程序员,自当闻过则喜,搞清楚弄明白。
先讲const,这玩意儿怎么翻译我也拿不准,C语言中该关键字的用法比较简单,大概有如下几种用法:
[1] 修饰普通变量:变量只读,在程序运行过程中不可修改。
- const int i = 100; //i is read only
- i = 200; //compile error, variable i can not assignable
[2] 修饰指针 const T* p:表示不能通过p去修改p指向对象的内容,另一方面只能通过p调用T类的const成员函数
- const struct Foo *f = new Foo;
- f->dataX = 100; //compile error
- const char* p = "abc";
- p[1] = 'x'; //compile error
- f->nonconst_member_function(); ///compile error (后面再讲)
[3] 修饰指针 T* const p:表示指针只能在初始化时设置指向,之后便不能修改指向。
- char s1[] = "abc";
- char s2[] = "xyz";
- char* const p = s1;
- p = s2; //compile error
[4] 修饰指针 const T* const p:表示既不能通过p修改它指向的对象,又不能更改p的指向。
- const char* const p = "abc";
- p[1] = 'B'; //compile error
- p = "xyz"; //compile error
[5] 修饰函数参数:c语言中const修饰参数反映的含义同上所述
小结:C语言中,const的用法差不多就这些,比较简单。
C++扩充了const的用法
[1] 修饰成员变量:const成员变量只能在初始化列表里做初始化,程序运行中不可修改;如果是const整型,则可以C++11标准之后直接初始化。
- struct Foo
- {
- Foo() : PI(3.15) {} // PI is initialized by initializer list
- const int c = 100; //C++11 support
- const float PI;
- };
[2] 修饰成员函数:表示该成员函数是只读函数,不会修改默认参数this的成员变量,如果修改会编译报错。
- class Foo
- {
- int m_money;
- public:
- int get_money() const //
- {
- return m_money;
- }
- int set_money(int money) const //
- {
- m_money = money; //修改了this->m_money;需去掉函数const修饰
- }
- };
[3] 修饰引用:引用是C++才有的语法特征,引用是别名,本质上跟指针差不多,所以const修饰引用跟修饰指针的语义和约束差不多。
- Foo f;
- const Foo& r = f;
- r.m_data = 1; //compile error
[4] C++中对const修饰指针的补充
- struct Foo
- {
- int const_member_function() const { return m_data; }
- int non_const_member_function(int data) { m_data = data; }
- int m_data;
- };
- int main()
- {
- const Foo* f = new Foo;
- f->const_member_function(); //OK
- f->non_const_member_function(); //compile ERROR
- return 0;
- }
为什么呢?因为const成员函数相当于承诺不会修改this的成员变量,而该承诺会被编译器检查,如果没有履行承诺,则编译器会报错。而const Foo* f意味着不能通过f去修改f指针指向变量的内部值。
通过f->data = 1的方式肯定是不行。
另一方面,你只能通过f去调用它的const成员函数,因为const成员函数的语义就是不会修改this的值,编译器很容易执行这个校验。
const修饰参数
const可以修饰普通参数,也可以修饰指针/引用参数,因为形参是实参的副本,所以const修饰普通参数其实没什么意义,我们着重讲讲const修饰指针/引用参数。
比如标准C库函数strcpy的签名:char *strcpy(char * dst, const char * src);
dst表示目标地址,src表示源串,const修饰了源串,这是因为从源串拷贝到目标串,不需要修改源串内容,这相当于向strcpy调用者承诺:
放心大胆的调用吧,strcpy函数实现保证不会修改src的内容,编译器会执行这种检查。
这样,在review代码的时候,如果想追踪src在哪里被修改了,当看到strcpy的签名,就不用打开函数去看实现,只要不违背承诺,肯定不是这个函数内改动了src。
const char *src是一种承诺,也是一种约束。调用的地方,const char*形式的形参,既传const char*实参,也可以传char*实参,因为参数const char*是更强的承诺。
但反之不成立。比如第一个参数dst是不带const的,那么如果有一个变量类型为const char* p,那不能把p作为第一个参数传递进strcpy,编译不过。
因为strcpy不承诺不修改dst,是一个更弱的承诺,只有声明为const指针的参数,才能传递const指针实参。
const其他
const还可以修饰返回值,还可以跟extern结合,但这些都是一些小语法技巧,一般开发用不太到,真碰到再查不迟。
const_cast有什么用?
const是C++的一个强制转换,它用来去掉const属性,比如:
- Foo foo;
- const Foo *f1 = &foo;
- Foo* f2 = const_cast
(f); - Foo* f3 = (Foo*)f;
const_cast的作用跟强转差不多,C++加const_cast主要是为了功能完整性,const_cast作用于引用跟作用于指针差不多。
为什么说const_cast几乎都反应接口设计有问题
程序设计要言行一致,遵守承诺,这意味着:不应该把参数声明为const指针,而函数实现里借助强制去掉const属性。
首先,这样做是危险的,比如const char* p = "abc"; p指向常量字符串被作为参数传递,被强转+修改,则会导致程序crash。
其次,这样做是分裂的,因为你加const修饰相当于让编译器帮你执行检查,以便在你违背承诺的时候通过编译期检查报错提醒你,但在它真正向你报错的时候,你又说别管啦,老子就是要蛮干。
const_cast或者通过c风格强转,基本上都暴露出设计上的问题。
设计良好的程序基本上不需要const强转。因为const约束在调用链会传播,所以,你需要一以贯之的遵守约定,找到导致需要const强转的错误源头,这可能会多费一点时间,但它是值得的。
const没有区分编译期常量和运行期常量,constexpr是C++11开始提出的关键字,被限定为编译器常量,其意义与14版本有一些区别。
C++11中的constexpr指定的函数返回值和参数必须要保证是字面值,而且必须有且只有一行return代码,这给函数的设计者带来了更多的限制,比如通常只能通过return 三目运算符+递归来计算返回的字面值。
而C++14中只要保证返回值和参数是字面值就行了,函数体中可以加入更多的语句,方便了更灵活的计算。
这里我们主要讲constexpr和const的区别。
constexpr可以用来修饰变量、函数、构造函数。一旦以上任何元素被constexpr修饰,那么等于说是告诉编译器 “请大胆地将我看成编译时就能得出常量值的表达式去优化我”。
- constexpr func()
- {
- return 10;
- }
- int main()
- {
- int arr[func()];
- }
编译期大胆地将func()做了优化,在编译期就确定了func计算出的值10而无需等到运行时再去计算。
这就是constexpr的第一个作用:给编译器足够的信心在编译期去做被constexpr修饰的表达式的优化。
constexpr还有另外一个特性,虽然它本身的作用之一就是希望程序员能给编译器做优化的信心,但它却猜到了自己可能会被程序员欺骗,而编译器并不会对此“恼羞成怒”中止编译。
C/C++程序应该积极的使用const/constexpr,什么叫积极使用?只要有可能,那么我们就应该用const/constexpr。
只要可能就应该用xx,这种话一般而言都是错的,但用在const/constexpr却很正确,因为使用const/constexpr基本上都会让你的程序更健壮、更快,const修饰的整型变量,在gcc开优化选项的时候,有可能被直接编译到汇编代码指令,而非生成一个变量,而constexpr的优化作用在前面一节已经阐述。
与之对应的是:只要有可能,就不要使用const_cast,它基本上都反映了接口设计上的问题。
就酱,信不信随你!
标题名称:一文讲清C/C++ Const/Const_Cast/Constexpr
文章URL:http://www.gawzjz.com/qtweb2/news46/11046.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联