热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++中的const讲解---《EffectiveC++》

条款三:尽可能使用const为什么我们推荐尽可能使用const呢?因为在预编译文件中定义宏和const效果相似,但是宏定义很麻烦而且超容易出错,更重要的是预编译器可能会很早拿走里面的

条款三:
尽可能使用const

为什么我们推荐尽可能使用const呢?因为在预编译文件中定义宏和const效果相似,但是宏定义很麻烦而且超容易出错,更重要的是预编译器可能会很早拿走里面的东西,导致在编译器执行的时候找不到宏定义的内容,调试错误需要好久,为了避免这种麻烦,我们推荐尽可能的使用const!const作为C语言和C++语言中的一个神技,或多或少都有其独特的脾气,今天让我们探索一下const关键字吧!

条例一:const如果出现在指针左边,指针指向的对象是const对象,如const int* a=&b,也可以写成int const*a=&b,表明b是常量,其实b不一定是常量如果出现在指针号右边,则表示该指针是const,不能指向其他对象,如int const a=&b,注意这里有一个显著问题,就是

int b=10;
const int*a=&b;
b=100;
cout<<*a<

想必大家都知道答案了吧,就是100,为什么呢?说好的a指针指向的对象是常量呢?各位稍安勿躁,条例一指的是在当作为函数参数时候的特性,当不作为函数参数时候,由于b本来就是变量,随时都可以变,而a只是指向b的一个普通指针而已,相当于忽略掉const属性,所以当然可以改变呀!

条例二:const成员函数

由于const那么好用,下面我们讲一下const在类中的运用

class TextBlock{
public:
const char& operator[](std::size_t position) const{
return text[position];
}
//第一个const表明operator指向的是const对象,第二个const表明该重载函数不能对类的成员变量进行修改;
char& operator[](std::size_t position){
return text[position];
}
//这个重载函数只是简单的表示重载运算符,适用于非const对象;
private:
std::string text;
};

从以下代码的运行中,可以观察到,可以观察到第一个operator[]代表const对象,同时成员变量无法被修改,第二个operator[]代表非const变量,同时成员变量可以被修改。、

#include 
#include
using namespace std;
class TextBlock{
public:
TextBlock(string s){
this->text = s;
}
const char& operator[](std::size_t position)const{
cout <<"我为const代言" < return text[position];
}
char& operator[](std::size_t position){
cout <<"我为non-const代言" < return text[position];
}
private:
std::string text;
};
int main(){
const TextBlock tb("hello");
cout <0] < TextBlock tb1("hello");
cout <0] < tb1[0] = 'c';
cout <0] < return 0;
}

同样的,我们可以将string替换为char*表示,代码如下:

class TextBlock{
public:
...
cosnt& operator[](std::size_t position) const{
return pText[position];
}
private:
char* pText;
};
const TextBlock cctb("hello");
char* pc=&cctb[0];
*pc='J';//cctb现在有了"Jello"这样的内容

观察上面的代码,为什么此时cctb[0]的值就可以改了呢?注意operator[]的第二个const指的是不能修改成员变量的值,在这里成员变量的值是pText,pText有没有指向其他地址呀,没有吧,即成员变量的值没有被改变呀,因此肯定可以修改呀!

如果我们想要在不准备修改成员变量的成员函数中想要修改成员变量呢?有些拗口,请看如下代码:

class CTextBlock{
public:
...
std::size_t length() const;
private:
char* pText;
std::size_t textLength;
bool LengthIsValid;
}
std::size_t CTextBlock::length() const{
if(!lengthIsValid){
textLength=std::strlen(pText);
lengthIsValid=true;
}
return textLength;
}

上面代码有木有错呢,当然有错,在const成员函数中修改成员变量,如果我们想要其变为正确的怎么办呢?答案很简单,就是将想要更改的变量声明为mutable即可。

条例三:
在const和non-const成员函数中避免重复

怎么解决呢?C++给出的建议是在non-const成员函数中调用const成员函数,为什么不能烦着来呢?const版本中调用non-const版本,注意const成员函数承诺不改变其对象的逻辑状态,non-const成员函数并没有这样的承诺,如果const调用non-const函数就是冒了这样的奉献,因此我们不这样调用,具体怎样实现的呢?请看如下代码:

class TextBlock{
public:
...
const char& operator[](std::size_t position) const{
...
return text[position];
}
char& operator[](std::size_t position){
return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]]);
...
}

条例4:顶层const和底层const作为重载函数须知
顶层const不影响传入函数的对象,一个拥有顶层const的形参无法和一个没有拥有顶层const的形参区分开来
Record lookup(Phone);
Record lookup(const Phone);

Record lookUp(Phone*);
Record lookUp(Phone* const);
等由于都是顶层const所以每一组的第一个和第二个都一样,无法区分;

底层const确实可以区分的,如果形参是某种类型的指针或者引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载,此时const是底层的。
Record lookup(Account&);//作用与Account引用
Record lookup(const Account&);//作用于常量引用

Record lookup(Account*);//作用于指向Account的指针
Record lookup(const Account*);//作用于指向常量的指针
为了更清楚地理解,我编写了如下的函数:

void record(int &a){
cout <<"hahaha:" <}
void record(const int&a){
cout <
}
int a = 10;
const int b = 100;
int &a1 = a;
const int &b1 = b;
record(a1);
record(b1);

可以看看运行结果:
这里写图片描述
PS:
突然发现自己一直对顶层const和底层const的理解有误,紧急补充一下哈~
顶层const:指针本身是个常量,即const出现在指针右侧;
底层const:指针所指向的对象是个常量,即const出现在指针左侧;


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • AtonepointIhadlookedatimplementingaclasstemplateinC++thatwouldsupportanEnumthatwo ... [详细]
  • Igotthiscode(IknowitsinSpanishIcantranslateifneeded)wheretheygivemethefunctionS ... [详细]
author-avatar
橄榄村
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有