zoukankan      html  css  js  c++  java
  • 刨根问底系列之C++ const 挖掘

    一、 const的作用:

         1、限定const指定的值的修改

              ex1.1:

              const int a = 2;

              //a = 3;  error: assignment of read-only variable

         就如C语言里宏一样,a会被放到符号列表里,不过a是内部链接的(内部链接是指只在当前文件内是可见的)。当不取a的地址的时候,系统不会给a分配内存,取a地址的时候就会给a分配地址,但改变a指向的内容并不能改变a的值,因为a已经被编译成为符号了。改变a内存所指内容是没有任何结果的。

              ex1.2:

    #include <iostream>
    using namespace std;
    int main() {
        const int ci = 2;
        cout<<"the addr of ci is:"<<(&ci)<<endl;
        int *p = const_cast<int*>(&ci);
        cout<<"the addr of p is:"<<p<<endl;
        *p = 5;
        cout<<"the value of ci is:"<<ci<<endl;
        cout<<"the value of p is:"<<(*p)<<endl;
        return 0;
    }
    

              输出结果为:

              

         2、限定函数返回值的修改,限定函数内容的修改

              函数返回值加上const,防止赋值运算,member function加上const 限定,防止对象member data修改。

              ex1.3:

    #include <iostream>
    using namespace std;
    class Test{
        public:
            Test();
            ~Test();
            Test& GetTest() {
                return *this;
            }
            const Test& GetConstTest(){
                return *this;
            }
    
            const Test& operator=(const Test& other) {
                this->value_ = other.value_;
                return *this;
            }
    
            int ChangeValue(int value) const {
                //value_ = value;   error: value_ is read only
                return value_;
            }
        private:
            int value_;
    };
    int main() {
        Test test;
        test.GetTest() = test;
        //test.GetConstTest() = test; //error can't assignment to return value
        return 0;
    }
    

              在函数member function GetConstTest() 里返回值是const属性的,所以不能为返回值赋值。在ChangeValue里member function 被限定为const 成员函数,所以在内部不能修改member data value_ 的指。

         3、程序的可读性

              加上const限定,可以很清楚的告诉编译器和程序员,这个数值不可以修改。同时将函数参数定义为const 引用,这样和传递值的感觉是一样的,防止程序传递整个对象。

         4、程序的效率

              在函数参数的传递过程中,变量都是按值拷贝传递的,如果是内置类型的话,占用内存空间少,拷贝一下数值无关紧要。但是自定     义类就没想像的简单了。在参数传递过程中,如果是按值传递的话,对象会调用自己的构造函数,并且将整个对象内容拷贝过去,这对于占用内存较多的类还是非常损耗效率的。如果定义为引用或者指针传递的话拷贝指针值就可以了。

         5、代替部分宏的职责

              C语言之所以在发明的时候受到了各方程序员的万般宠爱,很大一部分原因就是C语言里的宏。宏不仅可以定义全局数据符号,并且还可以用来构造非常精妙的函数。定义常用的变量,常用的函数非常方便。在方便的同时也有很多问题,比如说没有类型检查,只是机械的替换,比如说经典的”Max 宏函数“各种错误。看下面的例子。

              ex1.4:

    #include <iostream>
    using namespace std;
    #define PI 3.14
    #define Log(str) cout<<str<<endl
    #define Max(a, b) a > b ? a : b
    
    int main() {
        int a = 12;
        int b = 5;
        int max = Max(a, b);
        Log(PI);
        Log(max);
        Log("hello, world");
        return 0;
    }
    

              但是通过C++里的const就能很好的规避一些问题

              1、类型检查

              2、名称冲突,因为宏定义变量是外链接的

              3、调试代码效率问题上,如果在宏变量的地方出错了,编译器只是将宏变量代替为值,所以当看到对应的值的时候,会非常奇怪这个值是那里来的,但是对于const变量可以很清楚的知道是那个变量。


    二、const的用法

         1、限定内置常量

              限定常量很简单,在定义const变量的时候必须初始化,初始化的值可以是常量,也可是变量。

              ex2.1:

         2、限定指针和引用

              指针地址是程序运行的时候为变量分配的内存,所以const指针是不需要初始化的。由于const放的位置不同,对应限制的值也不同。通用的方法就是看const和变量的位置。

        int num = 2;
        int other = 3;
    
        // assignment
        const int* ptr1 = &num
        int const* ptr2 = &num
        int *const ptr3 = &num
        const int* const ptr4 = &num
    
        // change value
        ptr1 = &other;
        ptr2 = &other;
        // ptr3 = &other;     // read only error
        // ptr4 = &other;     // read only error
    
        // *ptr1 = other;     // read only error
        // *ptr2 = other;     // read only error
        *ptr3 = other;     
        // *ptr4 = other;     // read only error
    


         3、限定对象

         const 在限定对象使用要点:

         1、按位限制,对象占用的内存不可改变,将this指针转为非const指针就可以改变member data。

         2、按逻辑限制,对象中的数据成员限制,在const member function 中值申明为mutable 就可以改变。

         3、const member data 必须在初始化列表里初始化完。

         4、在class 内部只有char, int, long, float, double可以通过static const 申明的时候赋值。

         ex2.3

    #include <iostream>
    using namespace std;
    
    const int MAX_FRIEND = 100;
    class Player{
        public:
            enum {
                boy = 1,
                girl = 0
            };
            Player() : user_id_(0), user_sex_(boy){}
            ~Player(){}
    
            Player(const Player&);
            const Player& operator=(const Player&);
    
            void SetUserId(int user_id);
            int GetUserId() const;
    
            void SetGroupId(int group_id) const;
            int GetGroupId() const;
    
            void SetUserAge(int user_age) const;
            int GetUserAge() const;
    
            void SetUserName(const char* user_name);
            void PrintPlayerInfo() const;
    
        private:
            int user_id_;
            mutable int group_id_;
            int user_age_;
            string user_name_;
            const char user_sex_;
            static const int friend_count_ = MAX_FRIEND;
    };
    
    Player::Player(const Player& player):user_sex_(boy) {
    
    }
    
    const Player& Player::operator=(const Player& other) {
    
    }
    
    void Player::SetUserId(int user_id) {
        user_id_ = user_id;
    }
    
    int Player::GetUserId() const {
        return user_id_;
    }
    
    void Player::SetUserAge(int user_age) const {
        const_cast<Player*>(this)->user_age_ = user_age;
    }
    
    int Player::GetUserAge() const {
        return user_age_;
    }
    void Player::SetGroupId(int group_id) const {
        group_id_ = group_id;
    }
    
    int Player::GetGroupId() const {
        return group_id_;
    }
    
    void Player::SetUserName(const char* user_name) {
        user_name_ = user_name;
    }
    
    void Player::PrintPlayerInfo() const {
        cout<<"user id:\t"<<user_id_<<endl;
        cout<<"user name:\t"<<user_name_<<endl;
        cout<<"user sex:\t"<<user_sex_<<endl;
        cout<<"user age:\t"<<user_age_<<endl;
        cout<<"user group:\t"<<group_id_<<endl;
    }
    int main() {
        const Player player1;
        //player1.SetUserId(100001);
        player1.GetUserId();
    
        Player player2;
    
        player2.SetUserId(100001);
    
        player2.SetGroupId(100);
    
        player2.SetUserAge(21);
    
        player2.SetUserName("Jack");
    
        player2.PrintPlayerInfo();
        return 0;
    }
    

    通过例子2.3可以看出const objects只能读取内存的值,不能改写内存的值。对于const member function,member data group_id_ 是按逻辑申明的可改变变量。而在SetUserAge(int user_age)函数里通过强转this指针,来改变member data。

         文章里所示程序在gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)环境里编译通过,全文完。

    参考:

    c++ 编程思想卷一

    effective c++ 第三版

  • 相关阅读:
    YOLO V2 代码分析
    HDU 1728 逃离迷宫【BFS】
    POJ 2987 Firing【最大权闭合图-最小割】
    POJ 2914 Minimum Cut【最小割 Stoer-Wangner】
    模拟C#的事件处理和属性语法糖
    c版基于链表的插入排序(改进版)
    一句话概述代码的用途
    用python实现的抓取腾讯视频所有电影的爬虫
    jquery 实现智能炫酷的翻页相册效果
    KISSY(JS)炫动导航,缓动应用实例(^_^)
  • 原文地址:https://www.cnblogs.com/fengju/p/6174331.html
Copyright © 2011-2022 走看看