IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> EffectiveC++-条款03:尽可能使用const -> 正文阅读

[C++知识库]EffectiveC++-条款03:尽可能使用const

尽可能使用const

1. 含义

const关键字使得你可以指定一个语义约束(也就是指定一个不该被改动的对对象),const可以作用于任何对象,包括变量,函数,类等等。

2. 用法

结合*(指针)使用时,
如果关键字const出现在星号左边,表示被指物是常量。(这里的常量是指通过指针不可修改它的值,并不代表被指物本身就是常量)
如果关键字const出现在星号右边,表示指针是常量。
如果关键字const出现在星号左右两侧,表示指针和被指物都是常量。

如下是代码测试

int A=10;
int *PA=&A;
const int * PCA=&A;
int * const CPA=&A;
const int *const CPCA=&A;

FFunctionLibrary::Println(*PA);
*PA=100;//被指物可修改
PA=&A;//指针可以修改
FFunctionLibrary::Println(*PA);
    
FFunctionLibrary::Println(*PCA);
//*PCA=1;被指物不可修改
PCA=&A;//指针可以修改
    
FFunctionLibrary::Println(*CPA);
*CPA=1;//被指物可以修改
//CPA=&A; 指针不可重新赋值,再赋与初值相同的值也不行
FFunctionLibrary::Println(*CPA);

//*CPCA=1;被指物不可赋值
//CPCA=&A;指针不可赋值
FFunctionLibrary::Println(*CPCA);

3. stl中的const

stl的迭代器基础是指针,所以迭代器的作用就像个T *指针。
声明迭代器为const就像T * const。表示指针不改变,可以改内容。
对应的,声明常量迭代器就像const T *,表示指针可变,不可修改内容。

如下是代码测试

std::vector<int>Vector;
for(int i=0;i<10;++i)
{
    Vector.push_back(i);
}
const std::vector<int>::iterator Iterator=Vector.begin();
*Iterator=10;//所指物可以修改
//Iterator++;迭代器不可修改

std::vector<int>::const_iterator ConstIterator=Vector.begin();
//*ConstIterator=10;所指物不可修改
ConstIterator++;//指针可以修改
for (auto i=ConstIterator;i!=Vector.end();++i)
{
	FFunctionLibrary::Println(*i);
}

4. 函数返回值中的const

在返回值中使用const可以避免一些错误。
我们先看一个例子

const? AConst& operator*(const AConst&Other)
{
    this->IntNumber=this->IntNumber*Other.IntNumber;
    return *this;
}
operator bool()
{
 	return true;
}
AConst A;
AConst B;
AConst C;
FFunctionLibrary::Println((A*B).IntNumber);//10000
if (A*B=C)
{
	FFunctionLibrary::Println("Ohhhhhhhhhhh");
}

我不知道为什么有人会对两个数值的乘积再做一次赋值,但我知道会有很多程序员会在无意识中那么做。(Moota:emmmm…)

假如你的类型支持隐式的bool类型转换,并且*运算符返回的是一般的引用,这样的代码编译是可以通过的,但逻辑上存在很大的问题。如果使用常引用返回值的函数可以避免这样的问题,对常引用赋值会直接报错。

5. const成员函数

确认该成员函数可以作用于const对象

5.1 为什么需要?

  • 它使得class接口容易理解。这是因为得知哪个函数可以修改对象内容哪个不可以,是很重要的。

  • 它们使得“操作const对象”成为可能,这对于编写高效的代码是个关键。

  • 许多人漠视一件事实:两个成员函数如果只是是常量性不同,可以构成重载。
    如下是测试代码

        const int& operator[](int index)const
        {
            return IntNumber;
        }
        int& operator[](int index)
        {
            return IntNumber;
        }
    
    	AConst Const;
    	Const[1]=99;//普通对象返回引用
        FFunctionLibrary::Println(Const.IntNumber);
        const AConst ConstConst;
        //ConstConst[1]=1;常对象返回常引用,可读不可写
        FFunctionLibrary::Println(ConstConst.IntNumber);
    

    通过测试可以得知,常对象会调用带const修饰的函数,即常函数。

6. 额外的注意

对于非引用的类型,const意义不大,函数返回的将是一个副本,不会更改原来引用所指向的数据,想必这不是你所期望的行为。

7. Const的哲学

成员函数为const意味着什么?
这里有两个流派

  • bitwise constness(又称physical constness)
  • logical constness
    有什么区别?
    bitwise const阵容的人相信,成员函数只有在不更改对象的任何成员变量时才可以说是const。这也容易实现,编译器只要检测成员变量的赋值操作即可。
    然而这存在缺陷。
    比如指针。我保证不修改指针指向谁,但我可以修改指针指向对象的值。
    这种情况导出了logical constness。这一流派的人主张,一个const成员函数可以修改它所处理的对象的某些值,但只有在客户端侦测不到的情况下才得以如此。

比如在常函数里面除了对常变量的使用,还可能包含一些变量的使用。但是编译器不同意,这时候可以使用 mutable 关键字,修改变量的常量性。

const int ConstIntNumer=100;
mutable std::string UseConstIntNumberPeople="Moota";
void AConst::UseConstIntNumber(std::string Name) const
{
    //Todo about Number;
    UseConstIntNumberPeople=Name;
}

8. 避免const和non-const实现的重复

对于大多数函数而言,可能就是返回值上具有常量和非常量之分,也就是说存在大量相同的代码,这是我们不想要看到的。
你可以选择把相同的代码封装成函数,但是你还是重复了一些代码,包括函数的调用,两次return语句。
一个比较理想的方法是使其中的一个调用另一个的实现。
而一般的,我们建议在non-const函数调用const函数的实现,为什么?
如果const函数调用non-const函数的实现,那是一件糟糕的事情,因为const函数承诺不修改其对象的逻辑状态,但如果去调用non-const函数,就可能冒着修改对象的风险,这是坏代码的前兆。而且,如果这样的代码通过编译,意味着得先将this指针的const性质先去掉,这存在很大风险。

non-const转const测试代码

const int& operator[](int index)const
{
   return IntNumber;
}
int& operator[](int index)
{
	//return IntNumber;
	return const_cast<int&>(static_cast<const AConst&>(*this)[index]);
}

static_cast负责将*this 对象转换成常对象,这样才能调用常函数。
const_casr负责将常函数返回的常引用转换成普通引用。

总结

  • 将某些东西声明为const可帮助编译器侦测出错误用法,const可被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体等等。
  • 编译器强制实施 bitwise constness,但是你编写程序时应该使用logic constness。
  • 当const和non-const 成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:13:21  更:2022-03-15 22:17:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:41:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码