• const成员函数, const member function


    起源

    上周在写talk的OnlineStatManager的时候(一个用于管理用户在线类型的类),  其中有个private member.

    private:
        OnlineType getStat(int userId) const ;

    用来读出user的在线类型, 我把这个member声明为了const , 在读map的时候加读锁,  锁用到了自己定义的类成员 boost::shared_mutex mu_;   截取相关代码如下

     1 class OnlineStatManager {
     2 // ...
     3 private:
     4          OnlineType getStat(int userId) const;
     5          boost::shared_mutex mus_[POOL_NUM]; //应该为 mutable boost::shared_mutex mus_[POOL_NUM];
     6 }
     7 OnlineType OnlineStatManager::getStat(int userId) const{
     8            //...
     9            ReadLock read(mus_[poolIndex]);
    10            //...
    11 }
    12 //typedef boost::shared_lock<boost::shared_mutex> ReadLock; 

    上面的第9行代码就编译不过了,ReadLock的定义如下:

    typedef boost::shared_lock<boost::shared_mutex>  ReadLock;

    g++给出的错误信息是:  

      boost::shared_lock<boost::shared_mutex>::shared_lock(const boost::shared_mutex&)’ 的调用没有匹配的函数

    这里需要注意的是,  shared_lock的 constructor都是传的 reference, 但是在下面的测试程序中可以看到const member function在使用自己类成员的时候都是变成const 引用去用的, 把第5行mus_的声明加上mutable或去掉getStat声明和定义时的const就行了.

    const 成员函数

    在c++的语法层面来看就是const class object只能调用其public 的const member(function)(当然我们一般不会把data member作为public成员), 而const member function不能修改data member的值

    我自己的结论是在类的const member function中,  编译器把类所有的成员(field)都看作是const类型的, 来进行编译,(这也是为什么const 成员函数在声明和定义中都要写 const 关键词),  相当于在Class C 的 member function中, this 的行为就像它们被如下声明(在类成员函数内部可以直接访问该类对象的private member)

    C * const this; // non-const member function
    const C * const this; // const member function

    effective c++ 中的item 21这样说到  :    use const whenever possible

    其中提到两个const概念,    bitwise constness and conceptual constness(按位常量和概念性的常量),    前者是对基本类型来说的而且也是c++对 constness的定义,  对Class来说,  const object只能调用其public的 const member(function), 且const member function不能修改类对象的fields,  但是又考虑到 conceputual constness的概念,    C++ standard commission对此的解决方案就是mutable,  mutable可以使类成员不受const member function的限制, 而可以被赋值修改

    use const whenever possible的原则, 在多人合作写程序的时候, 则更应该都去遵循这个原则,   且还可能常会遇到这种类型转换的错误  

    另外不能用iterator去遍历一个const container, 要用const_iterator,    这个我还没细想 ,以后会写一篇细研究一下

    一个测试程序 

    写了个测试程序 const_function.cpp, 有些杂乱,    const T 是可以转换 T  , 但是const T& 不能转换到 T&

    #include <iostream>
     // const int  可以到 int 不能到 int& , 在参数传递中 
     using namespace std;
     int global (int& num){
         num = num + 2;    
     }
     class Int{
     public :
             Int (int& i) :i_(i){
                 cout << "Int 's constructor" << endl;    
             }
     
             Int () {
                 cout << "Int 's default constructor" << endl;    
             }
     
             int i () const{
                 return i_;    
             }
     private :
             int i_;
     };
     class WY{
     public :
             WY (int num) : num_(num) {
                 cout << "WY's constructor WY(int num)" << endl;    
             }
             
             WY (Int& in) : in_(in) {
                 cout << "WY's constructor WY(Int& in)" << endl;
                 num_ = in.i();    
             }
     
             int get() const{
                 cout << "int get() const" << endl;
                 Int in(num_);
                 WY w(in_);
                 w.num_ = 7;
                 int temp = global(num_);  //这儿错了, temp是global的地址了
                 return num_;
             }
     
     private :
             mutable int num_;
             mutable Int in_;
     };
     int main (){
         WY wy(5);
         int t = wy.get();
         cout << "t = " << t << endl;    
     }
    

    代码定义了两个类, 一个全局函数,  主要是int WY::get() const中, 用自己的两个data member作为参数去生成两个类, 和去调用全局函数

    如果,48,49行没有把类成员声明为 mutable, 则编译不过 , 会出现如下编译错误

    const.cpp: In member function ‘int WY::get() const’:
    const.cpp:36:15: error: no matching function for call to ‘Int::Int(const int&)’
    const.cpp:36:15: note: candidates are:
    const.cpp:13:3: note: Int::Int()
    const.cpp:13:3: note:   candidate expects 0 arguments, 1 provided
    const.cpp:9:3: note: Int::Int(int&)
    const.cpp:9:3: note:   no known conversion for argument 1 from ‘const int’ to ‘int&’
    const.cpp:7:7: note: Int::Int(const Int&)
    const.cpp:7:7: note:   no known conversion for argument 1 from ‘const int’ to ‘const Int&’
    const.cpp:37:12: error: no matching function for call to ‘WY::WY(const Int&)’
    const.cpp:37:12: note: candidates are:
    const.cpp:29:3: note: WY::WY(Int&)
    const.cpp:29:3: note:   no known conversion for argument 1 from ‘const Int’ to ‘Int&’
    const.cpp:25:3: note: WY::WY(int)
    const.cpp:25:3: note:   no known conversion for argument 1 from ‘const Int’ to ‘int’
    const.cpp:23:7: note: WY::WY(const WY&)
    const.cpp:23:7: note:   no known conversion for argument 1 from ‘const Int’ to ‘const WY&’
    const.cpp:39:26: error: invalid initialization of reference of type ‘int&’ from expression of type ‘const int’
    const.cpp:4:5: error: in passing argument 1 of ‘int global(int&)’
    

    仔细看看这个错误输出,错误就发生在源代码的36,37,39行,而且错误输出中的no matching function中的参数写的是引用,这里暂时不是很明白,再看下面,果然from 'const int'  to 'int&'  , 'cont Int' to 'Int&'  ,可以看到在get()这个const成员函数中把两个成员int, Int都作为const在用

    修正后的运行结果

    Int 's constructor Int()
    WY's constructor WY(int num)
    int get() const
    Int 's constructor Int(int i)
    WY's constructor WY(Int& in)
    t = 7

    运行结果还可以看出, WY类对象先初始化自己的类成员 Int in,  再执行自己的constructor


    参考 http://en.wikipedia.org/wiki/Mutable,  对immutable object有一些介绍

  • 相关阅读:
    这两年
    Ubuntu 14.04 更新 setuptools 至 19.2 版本
    leetcode 编译问题:Line x: member access within null pointer of type 'struct TreeNode'
    C++ 将 std::string 转换为 char*
    LeetCode in action
    Ubuntu下 fatal error: Python.h: No such file or directory 解决方法
    Mac OS X 清除DNS缓存
    Mac OS X 避免产生临时文件 .DS_Store
    Mac OS X 显示和隐藏文件
    解决 ln -s 软链接产生的Too many levels of symbolic links错误
  • 原文地址:https://www.cnblogs.com/livingintruth/p/2360319.html
Copyright © 2020-2023  润新知