热门标签 | 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出现在指针左侧;


推荐阅读
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 本文总结了Java初学者需要掌握的六大核心知识点,帮助你更好地理解和应用Java编程。无论你是刚刚入门还是希望巩固基础,这些知识点都是必不可少的。 ... [详细]
  • C语言中全部可用的数学函数有哪些?2.longlabs(longn);求长整型数的绝对值。3.doublefabs(doublex);求实数的绝对值。4.doublefloor(d ... [详细]
  • IOS Run loop详解
    为什么80%的码农都做不了架构师?转自http:blog.csdn.netztp800201articledetails9240913感谢作者分享Objecti ... [详细]
  • String字符串与字符数组#includeStringintmain(){char*strhello;字符串与字符数组的关系:字符串是 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 本文介绍如何使用线段树解决洛谷 P1531 我讨厌它问题,重点在于单点更新和区间查询最大值。 ... [详细]
  • 字节流(InputStream和OutputStream),字节流读写文件,字节流的缓冲区,字节缓冲流
    字节流抽象类InputStream和OutputStream是字节流的顶级父类所有的字节输入流都继承自InputStream,所有的输出流都继承子OutputStreamInput ... [详细]
  • 在C语言中,指针的高级应用及其实例分析具有重要意义。通过使用 `&` 符号可以获取变量的内存地址,而 `*` 符号则用于定义指针变量。例如,`int *p;` 定义了一个指向整型的指针变量 `p`。其中,`p` 代表指针变量本身,而 `*p` 则表示指针所指向的内存地址中的内容。此外,指针在不同函数中可以具有相同的变量名,但其作用域和生命周期会有所不同。指针的灵活运用能够有效提升程序的效率和可维护性。 ... [详细]
  • 具备括号和分数功能的高级四则运算计算器
    本研究基于C语言开发了一款支持括号和分数运算的高级四则运算计算器。该计算器通过模拟手算过程,对每个运算符进行优先级标记,并按优先级从高到低依次执行计算。其中,加减运算的优先级最低,为0。此外,该计算器还支持复杂的分数运算,能够处理包含括号的表达式,提高了计算的准确性和灵活性。 ... [详细]
  • 无论是计算机专业学生还是非计算机专业的学习者,在掌握C语言的过程中可能会遇到诸多挑战,不清楚从何入手。为此,本文系统地梳理了2019年福建省C语言的核心知识点,并结合最新的技术进展进行了详细总结,旨在为初学者提供全面的学习指导。文章不仅涵盖了基础语法和数据结构,还深入探讨了指针、内存管理和算法优化等高级主题,帮助读者快速提升编程能力。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
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社区 版权所有