effective C++读书笔记(三)尽量使用const

本文详细介绍了C++中常量的使用,包括常量与指针、函数的关联,以及如何正确理解并运用const、non-const、const pointer和non-const pointer的概念。通过实例分析了常量指针、指针常量、常量指针常量的区别,并探讨了迭代器(iterator)与指针的相似性。同时,阐述了const修饰函数的用途和注意事项,以及如何避免误操作导致的类型混淆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Item 3:尽量使用常量Const

总述:使用常量好的的地方在于它定义了一个语义上的常量—一个不能修改的特别对象,并且编译器会强制它是常量。常量是多功能的,可以修饰全局变量和局部变量,同样能修饰静态static变量、函数、指针等。

 

Const With Point常量与指针

  在学c/c++时候我们最头疼的就是区分一些概念和定义,比如常量指针,指针常量,常量指针常量...,下面我们来看这三者怎么区分的。

char greeting[]="hello";

char *p1=greeting;                //non-const pointer,non-const date

const char *p2=greeting;          //non-const pointer,const date

char * const p3=greeting;         //const pointer,non-const date

const char * const p4=greeting;   //const pointer,const date

p1char型指针;p2是指针常量,即不能通过p2改变指针地址所对应的值;p3是常量指针,既不能改变p3地址,p4是常量指针常量,即不能改变指针地址也不能通过指针改变值。C++创始人Bjanre给出的记忆方法是从右往左读,const *p表示指针(‘*’)常量(“const”),

*const p表示常量指针。值得注意的是const char *pchar const *p是完全一样的,读者应该适应这两种写法。

  STL iterator是一种广义指针,因此iterator表现得和指针T*一样。定义iterator const表示常量指针,即iterator不允许指向其他地方;定义const_iterator表示指针常量,即不允许iterator改变它对应地址的值。具体用法如下:

std::vector<int> vec;

...

const std::vector<int>::iterator iter=vec.begin();//iter act like T* const

*iter=10;//ok,changes what iter points to

++iter;  //error!iter is const

 

std::vector<int>::const_iterator cIter=vec.begin();//cIter act like const T*

*cIter=10;//error! *cIter is const

++cIter;  //ok,changes cIter

关于迭代器iterator的讨论见        

 

Const With  Function

  const最常用的就是修饰函数,在函数声明中限定函数返回类型,参数乃至整个函数。

对函数参数进行const限定的好处在于函数内不会改变参数值,这一点对按值引用和指针参数特别有用。这一部分以一些反例来说明问题。

Example1 返回类型限定为const能避免错误

  有如下声明:

class Rational{...};

const Rational operator *(const Rational &lhs,const Rational &rhs)

{...}

  很多人都疑惑为什么要限定放回类型为const,其实如果不限定为const的话,就可能会发生错误。

你可能不会写如下代码

Rational a,b,c;

...

(a*b)=c;

但是你很有可能写如下代码

if(a*b=c)...

当然,你的本意是if(a*b==c),但由于笔误,很有可能就写成if(a*b=c),不过现代编译器会给出警告。良好的编程习惯是限定operator*的返回类型为const,这样const就能阻止你对operator*的返回结果赋值。尽量使用const吧,这样你就能避免把’==’写成’=’。

 

 

Example2 const成员函数都可以用于const对象和非const对象,而非const成员函数只能用于非const 对象。

class X{

int aa;

public:

 void update(){a++;}

 int value() const {return aa;}

 void cheat() const {aa++}//error:aa is const

 }

 int g(X o1,const X & o2){

 o1.update();//fine:const对象调用非const成员函数}

 o2.update();//error:const对象只能调用const成员函数

 return o1.value()+o2.value();//fine:const对象和const对象都能调用const成员函数

}

 

 

 

Example3 强制去掉const,又名const不一定表现得和const一样。Bjanre在《c++语言的设计与演化》中提到:C++关心的是检查偶然的错误,而不是防止刻意的欺骗;我们不认为编译系统有责任去防止程序员明确地做突破类型系统的事。

 class cTextBlock{

 public:

 ...

 char & operator[](std::size_t position) const

 {return pText[position];}

 private:

 char *pNext;

 };

 const cTextBlock cctb("Hello");

 char *pc=&cctb[0];

 *pc='J';//cctb now is "Jello"

上面的cctbconst类型,但是通过指征*pc改变了它的值,const表现出非const效果。

 

 

 

Example4 const可变性与强制的平衡-mutable关键字。const是强制使变量不可变,但是有些时候你又想要某些改变,这就是mutable关键字引入的原因。

 class cTextBlock{

 public:

 ...

 std::size_t length() const

 private:

 char *pText;

 std::size_t textLength;//mutable std::size_t textLength

 bool lengthIsValid;//mutable bool lengthIsValid

 };

 

 std::size_t cTextBlock::length()const

 {

 if(!lengthIsValid){

 textLength=std::strlen(pText);

 lengthIsValid=true;

 }

 return textLength

 }

我们知道length()const是不能改变类成员值的,所以上面代码是错误的,解决方法是把成员函数length()声明为非const或者是像注释写的把textlengthlenhgthIsValid声明为mutable.

 

 

 

Example5 强制类型转换const_cast

这一个看不明白,先放一放,以后写。

 


内容概要:本文介绍了基于Python实现的SSA-GRU(麻雀搜索算法优化门控循环单元)时间序列预测项目。项目旨在通过结合SSA的全局搜索能力和GRU的时序信息处理能力,提升时间序列预测的精度和效率。文中详细描述了项目的背景、目标、挑战及解决方案,涵盖了从数据预处理到模型训练、优化及评估的全流程。SSA用于优化GRU的超参数,如隐藏层单元数、学习率等,以解决传统方法难以捕捉复杂非线性关系的问题。项目还提供了具体的代码示例,包括GRU模型的定义、训练和验证过程,以及SSA的种群初始化、迭代更新策略和适应度评估函数。; 适合人群:具备一定编程基础,特别是对时间序列预测和深度学习有一定了解的研究人员和技术开发者。; 使用场景及目标:①提高时间序列预测的精度和效率,适用于金融市场分析、气象预报、工业设备故障诊断等领域;②解决传统方法难以捕捉复杂非线性关系的问题;③通过自动化参数优化,减少人工干预,提升模型开发效率;④增强模型在不同数据集和未知环境中的泛化能力。; 阅读建议:由于项目涉及深度学习和智能优化算法的结合,建议读者在阅读过程中结合代码示例进行实践,理解SSA和GRU的工作原理及其在时间序列预测中的具体应用。同时,关注数据预处理、模型训练和优化的每个步骤,以确保对整个流程有全面的理解。
内容概要:本文详细介绍了如何使用PyQt5创建一个功能全面的桌面备忘录应用程序,涵盖从环境准备、数据库设计、界面设计到主程序结构及高级功能实现的全过程。首先,介绍了所需安装的Python库,包括PyQt5、sqlite3等。接着,详细描述了SQLite数据库的设计,创建任务表和类别表,并插入默认类别。然后,使用Qt Designer设计UI界面,包括主窗口、任务列表、工具栏、过滤器和日历控件等。主程序结构部分,展示了如何初始化UI、加载数据库数据、显示任务列表以及连接信号与槽。任务管理功能方面,实现了添加、编辑、删除、标记完成等操作。高级功能包括类别管理、数据导入导出、优先级视觉标识、到期日提醒、状态管理和智能筛选等。最后,提供了应用启动与主函数的代码,并展望了扩展方向,如多用户支持、云同步、提醒通知等。 适合人群:零基础或初学者,对Python和桌面应用程序开发感兴趣的开发者。 使用场景及目标:①学习PyQt5的基本使用方法,包括界面设计、信号与槽机制;②掌握SQLite数据库的基本操作,如创建表、插入数据、查询等;③实现一个完整的桌面应用程序,具备增删改查和数据持久化功能;④了解如何为应用程序添加高级特性,如类别管理、数据导入导出、到期日提醒等。 阅读建议:此资源不仅适用于零基础的学习者,也适合有一定编程经验的开发者深入理解PyQt5的应用开发。建议读者跟随教程逐步实践,结合实际操作来理解和掌握每个步骤,同时可以尝试实现扩展功能,进一步提升自己的开发技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值