【复读EffectiveC++03】条款03:尽可能使用const

本文详细探讨了C++中const关键字的用法,包括修饰变量、STL迭代器、函数参数和返回值,以及在面向对象中的类成员常量和函数中的应用。强调了const在提升代码健壮性和错误检测中的作用,以及const与mutable的区别和冲突处理策略。
摘要由CSDN通过智能技术生成

条款03:尽可能使用const

   条款02讲完了,条款03就针对02中提到的 const 关键字进行了用法上进行了拓展解释。

const 关键字:只要一个变量前用const来修饰,就意味着该变量里的数据只能被访问,而不能被修改,也就是意味着“只读”。

   const 关键字主要包括了如下几个应用方面:
   a、const 修饰 变量;
   b、const 与 STL迭代器;
   c、const 在函数中的应用;

一、const 修饰 变量

   在这一部分,基本就是条款02中提及的常量用法,把一个变量通过const修饰的方式变成常量,这里的变量,其实要涵盖指针的,在我的理解里,指针其实也是变量,是int型用来存储指向对象地址的特殊变量。
   其重要的还是要记住怎么分析const修饰的作用域,经典的分析例子就是const修饰指针,就可以总结为:
   const 在星号左边,被 指针指向的变量 为常量;在星号右边,则此指针本身是常量(指针指向的变量依然为变量)
   这样的修饰方式在某些文章中,也又别称,前者叫顶层 const ,底层 const,虽然个人觉得前后更贴切。

  还有就是面向对象扩展出来的类成员常量。
  类成员常量,表示成员变量在某个对象生存期内是常量,即在对象生成时给出常量值。
  而在此对象生存期内,它的值是不能改变的,只能初始化,不能赋值。同一个类的不同对象,不同对象对应的常量数据成员的值可以不同。
  常量成员变量只能初始化,其值只能在构造函数中设定,甚至不能在构造函数的函数体中通过赋值设定,只能在构造函数初始化列表中完成

二、const 与 STL迭代器

   STL,是标准模板库的缩写,其中包含着六个主要部分,容器、算法、迭代器、仿函数、适配器和分配器;
   STL 迭代器系以指针为根据塑模出来,所以迭代器的作用就像个T*指针,也因此迭代器同样具有只读的需求和设计。

 std::vector<int> vec;
 const std::vector<int>::iterator iter1 = vec.begin();
 std::vector<int>::const_iterator iter2 = vec.begin();

一句话,按指针的用法来即可。

三、const 在函数中的应用

  const在原来c语言函数中的应用,就是对函数进行只读限制,防止一些函数编写者不希望出现的变化。
  但本书讨论的是c++,其讨论的部分就要考虑两个部分:改版C语言的一般函数部分 和 面向对象扩展的特殊函数(成员函数)部分。

1、一般函数应用

  在一个一般函数里可以被const修饰的就两个部分:返回值和参数。
  const修饰返回值,也就是调用函数的结果不希望被修改:

const int Fun(int i_iValue)
{
    return 1;
}

  const修饰参数,也就是调用函数的参数不希望在函数体内被修改:

int Fun(const int i_iValue)
{
    return 1;
}

2、特殊函数(成员函数)应用

   特殊函数,其实就是原书中所说的类成员函数,之所以将其拿出来单独说,就是因为其涉及到面向对象中的重载。
   即,两个成员函数如果只是常量性不同(const成员函数与非const成员函数),是可以被重载。
   额外提一嘴,成员函数的参数用const修饰,其有一个经典的应用场景:拷贝构造函数。
  如上的原书例子:

class textBlock
{
public:
    char& operator[](std::size_t position){
        return text[position];
    }
    const char& operator[](std::size_t position)const {
        return text[position];
    }
private:
    std::string text;
};

textBlock tb("Hello");
std::cout << tb[0];  //调用非const版本的operator[]
tb[0] = 'x';  //正确
	
const textBlock ctb("World");
std::cout << ctb[0];  //调用const版本的operator[]
ctb[0] = 'y';  //错误

   这里,要针对常量性这个概念进行拓展,其表现为const修饰,但其含义是具有争议的,就是书中提及的 bitwise constness(位常量性)logical constness (逻辑常量性)
   bitwise constness是一个bit都不能动,即严格地要求const成员函数不更改任何成员变量(static除外),这个是C++编译器强制要求

class cTextBlock{
public:
    size_t length() const;
private:
    char pText;
    size_t textLength;
    bool lengthIsValid;
};
size_t cTextBlock::length() const{
    if(!lengthIsValid){
        textlength = strlen(pText);     //Error!
        lengthIsValid= true;            //Error!
    }
    return textLength;  
}

   logical constness是按逻辑区分哪些bits应该一动不动,哪些bits可以改动,即弹性地允许const成员函数修改一小部分成员变量。
   因此,当我们想要的编程模型是logical constness,而编译器是bitwise constness,两者之间可能存在冲突。

class CMyA
{
    int m_iValue1; 
    int m_iValue2;                  
    int* m_pValue; 

public:
   void Fun1(int index) const { //冲突1:没有修改实际数据,但是const函数中无法修改该值。
        m_iValue1++;    //Error!
        m_iValue2++;    //Error!
   }
   
    void Fun2(int x)  const //冲突2:修改了指针所指的数据,但是编译器仍然认为是const函数。
    {    
        *(m_pValue) = x;
    }
};

int main() {
    CMyA cA;
    return 0;
}

   冲突一,存在 在const修饰的成员函数内,必须改变部分成员变量 的需求,但bitwise不允许,解决办法是运用mutable或const_cast;
   冲突二,要着重解释一下:
   我们明明改变了m_pValue所指向变量的值,但编译器却没有报错。毕竟m_pValue是指针,指针是int变量,存放地址,我们没有m_pValue指向的空间,也就是说地址没有改变,也就是int值就没有改变。
   因此,冲突二解决办法,个人觉得没有,只能说,最好的做法是移除成员函数的const,不要让不知道这种情况的人出现错误理解导致更严重后果的发生

class CMyA
{
    mutable int m_iValue1;  // mutable关键字,在const函数中也可以修改该值 
    int m_iValue2;                  
    int* m_pValue; 

public:
   void Fun1(int index) const { //冲突1:没有修改实际数据,但是const函数中无法修改该值。
        m_iValue1++;
        const_cast<CMyA*>(this)->m_iValue2++;   // const_cast关键字,在const函数中也可以修改该值
   }
   
    void Fun2(int x) //冲突2:修改了指针所指的数据,但是编译器仍然认为是const函数。最好的做法:移除const
    {    
        *(m_pValue) = x;
    }
};

int main() {
    CMyA cA;
    return 0;
}

四、总结

1、将某些东西声明为const可帮助编译器侦测处错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
2、编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”。
3、当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

尾语:尽量使用const去提高代码的健壮性。

  • 19
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值