Item3:尽可能使用const

文章介绍了C++中的const关键字的用法,包括指针和指针所指对象的const、STL迭代器与const的关系、const成员函数的概念和重要性,以及如何通过mutable关键字处理逻辑上的const。此外,还讨论了如何避免const和non-const成员函数间的代码重复。
摘要由CSDN通过智能技术生成

0.概述

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

1.const简介

参考概述第一条。

修饰指针和指针所指物

  • 如果关键字const 出现在星号左边,表示被指物是常量(有些程序员会将关键字const写在类型之前,有些人会把它写在类型之后、星号之前。两种写法的意义相同);
  • 如果出现在星号右边,表示指针自身是常量;
  • 如果出现在星号两边,表示被指物和指针两者都是常量。

STL迭代器

STL迭代器的作用就像个T*指针。声明迭代器为const就像声明指针为const一样(即声明一个T* const 指针),表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。

如果希望迭代器所指的东西不可被改动(即希望STL模拟一个const T*指针),需要const_iterator:

std::vector<int> vec;
...
const std::vector<int>::iterator iter=vec.begin(); //iter类比T*const
*iter=10; //正确
++iter; //错误
std::vector<int>::const_iterator cIter=vec.begin(); //cIter类比const T*
*cIter=10; //错误
++cIter; //正确

函数声明:

在函数声明中,const可以指向函数的返回值;也可以指向各个形参;对于成员函数,还可以指向整个函数:

  • 令函数返回常量,可以降低因客户错误而造成的意外。
  • 对于const参数,除非有需要改动参数,否则都声明为const。
  • 下面详细展开const成员函数:

2.const成员函数

将const作用于成员函数上的目的是确定哪些成员函数可以作用于const对象上。这样做的意义有二:

  • 使class接口容易被理解(哪个函数可以改动对象内容,哪个函数不可)
  • 使操作const对象成为可能,有助于编写高效代码(改善C++代码效率的一个根本办法是以pass by reference-to-const的方式传递对象,而这样做的前提是有const成员函数来处理取得的const对象)

考虑下面的例子:

class TextBlock {
public:
    ...
    const char& operator[](std::size_t position) const // operator[] for
    { return text[position]; } // const objects
    char& operator[](std::size_t position) // operator[] for
    { return text[position]; } // non-const objects
private:
    std::string text;
};

调用示例:

std::cout << tb[0]; // fine — reading a non-const TextBlock
tb[0] = ’x’; // fine — writing a non-const TextBlock
std::cout << ctb[0]; // fine — reading a const TextBlock
ctb[0] = ’x’; // error! — writing a const TextBlock

 上述报错只因operator[]返回类型所致,operator[]调用动作本身没有问题。错误来源于试图对一个由const版本的operator[]返回的const char&进行赋值。

  • bitwise constness:成员函数只有在不更改对象之任何成员变量( static除外)时才可以说是const。也就是说它不更改对象内的任何一个bit。
  • logical constness:一个const成员函数可以修改它所处理的对象内的某些 bits,但只有在客户端侦测不出的情况下才得如此。

例:一个高速缓存文本区块的长度以便应付询问的类

class CTextBlock {
public:
    ...
    std::size_t length() const;
private:
    char *pText;
    std::size_t textLength; // last calculated length of textblock
    bool lengthIsValid; // whether length is currently valid
};
std::size_t CTextBlock::length() const
{
    if (!lengthIsValid) {
    textLength = std::strlen(pText); // error! can’t assign to textLength
    lengthIsValid = true; // and lengthIsValid in a const
    } // member function
    return textLength;
};

length的实现当然不是 bitwise const,因为textLength和 lengthIsvalid都可能被修改。如果编译器坚持 bitwise constness怎么办?

解决方法:利用mutable释放掉non-static成员变量的bitwise constness约束。

class CTextBlock {
public:
    ...
    std::size_t length() const;
private:
    char *pText;
    mutable std::size_t textLength; // 这些成员变量总是可以被更改
    mutable bool lengthIsValid; // 即使是在const成员函数内
};
std::size_t CTextBlock::length() const
{
    if (!lengthIsValid) {
    textLength = std::strlen(pText); // 可
    lengthIsValid = true; // 可
    } // member function
    return textLength;
};

3.在const和non-const成员函数中避免重复

如果成员函数执行很多操作,分别写const和non-const版本会造成大量的代码重复及伴随的编译时间、维护、代码膨胀等问题。

一种解决方案是将这些重复的代码移入另一个通常是private的成员函数并令const和non-const两个版本的函数调用它。但这样还是重复了一些代码:函数调用、两次return语句等。、

比较好的解决方案是实现operator[]函数的机能并使用它两次(一个调用另一个,非常量调用常量+转型操作),反之不行!

class TextBlock {
public:
    ...
    const char& operator[](std::size_t position) const // same as before
    {
        ...
        ...
        ...
        return text[position];
    }
    char& operator[](std::size_t position)
    {
        return const_cast<char&>( //转除const
            static_cast<const TextBlock&>(*this) //为*this加上const
                [position];
        );
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值