侧边栏壁纸
博主头像
如此肤浅

但行好事,莫问前程!

  • 累计撰写 52 篇文章
  • 累计创建 6 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

条款03 尽可能使用 const

如此肤浅
2022-05-14 / 0 评论 / 0 点赞 / 35 阅读 / 2,664 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-15,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. 将某些东西声明为 const 可帮助编译器侦测出错误用法;
2. const 尽可能地被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体;
3. 要注意下面”const 成员函数,案例一“中的情况;
4. 当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调用 const 版本可避免代码重复。

char greeting[] = "Hello";
char* p = greeting;	// non-const pointer, non-const data
const char* p = greeting;	// non-const pointer, const data
char* const p = greeting;	// const pointer, non-const data
const char* const p = greeting;	// const pointer, const data

const 出现在星号左边,表示被指物是常量;
const 出现在星号右边,表示指针自身是常量;
const 出现在星号两边,表示被指物和指针两者都是常量。

注意: 如果被指物是常量,有些程序员会将关键字 const 写在类型之前,有些人会把它写在类型之后、星号之前。两种写法的意义相同,所以下列两个函数接受的参数类型是一样的:

void f1(const Widget* pw);	// f1获得一个指针,指向一个常量的(不变的)Widget对象
void f2(Widget const * pw);	// 与f1相同

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;	// ok!改变iter所指物
++iter;	// error!iter是const

std::vector<int>::const_iterator cIter = vec.begin(); //cIter的作用像个const T*
*cIter = 10;	// error!*cIter是const
**cIter;	// ok!改变cIter

const 成员函数

将 const 用于成员函数的目的,是为了确认该成员函数可作用于 const 对象身上。

  • const 成员函数重要的原因:
    ① 使 class 接口比较容易被理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行,很是重的。
    ② 它们使“操作const对象”成为可能,使得更高效地编写代码。

  • 引入 mutable
    成员函数只有在不更改对象之任何成员变量(static除外)时才可以说是 const。
    若想让某个非 static 成员变量的值能被 const 成员函数修改,可以使用mutable

    案例一:

    class CTextBlock {
    public:
    	...
        // 该成员函数是const,函数内没有修改pText的指向,因此编译能通过。
        char& operator[] (std::size_t position) const
        { return pText[position]; }	
    private:
    	char* pText;
    }
    
    const CTextBlock cctb("Hello");	// 声明一个常量对象
    char* pc = &cctb[0]; // 调用operator[]取得一个指针,指向cctb的数据
    *pc = 'J'; // 修改了cctb的数据
    

    案例二:

    class CTextBlock {
    public:
    	...
        std::size_t length() const;
    private:
    	char* pText;
        mutable std::size_t textLength;	// const成员函数也可改变其值
        mutable bool lengthIsValid;	// const成员函数也可改变其值
    };
    
    std::size_t CTextBlock::length() const
    {
    	if(!lengthIsValid) {
        	textLength = std::strlen(pText);
            lengthIsValid = true;
        }
        return textLength;
    }
    
  • 在 const 和 non-const 成员函数中避免重复
    下面这段代码会有很多重复的部分,增加了编译、维护时间,有代码膨胀现象。

    class TextBlock {
    public:
    	...
        const char& operator[](std::size_t position) const
        {
        	...	// 操作一
            ...	// 操作二
            return text[position];
        }
        
        char& operator[](std::size_t position)
        {
        	...	// 操作一
            ...	// 操作二
            return text[position];
        }
    private:
    	std::string text;
    }
    

    因此,可以用 non-const 的函数调用 const 的函数,减少重复代码。

    class TextBlock {
    public:
    	...
        const char& operator[](std::size_t position) const
        {
        	...	// 操作一
            ...	// 操作二
            return text[position];
        }
        
        // 调用const的成员函数
        char& operator[](std::size_t position)	
        {
        	return 
            	const_cast<char&>( // 将op[]返回值的const转除
                	static_cast<const TextBlock&>(*this) // 为*this加上const
                    	[position] // 调用const op[]
                );
        }
    ...
    }
    

    注意: 不可使用 const 的函数调用 non-const 的函数!!!因为,使用 const 成员函数的目的是确保函数不会修改成员变量的值,而 non-const 成员函数可修改成员变量的值。若在 const 函数内调用 non-const 就会产生矛盾。相反,non-const 函数调用 const 函数不会出现这种问题。

0

评论区