菜鸟资源网站全面焕新升级啦!全新的界面设计,简洁而不失雅致,让您一目了然,轻松上手。我们还对资源分类进行了细致梳理,确保各类资源条理清晰,便于您按需筛选与查找。 立即查看

第十九章:尽可能多地使用 const,了解C/C++基本语言特性关键字【免费技术教程】

第十九章:尽可能多地使用 const,了解C/C++基本语言特性关键字【免费技术教程】

关键字是预先保留的标识符,每个关键字都有特殊的含义。程序不能使用与关键字同名的标识符。标准C++有63个关键字,根据关键字的作用,可以将其分为数据类型关键字和流程控制关键字两大类。正确而恰当地使用关键字可以有效地提高程序的质量,起到事半功倍...

当前版本

软件大小

软件语言

是否破解

关键字是预先保留的标识符,每个关键字都有特殊的含义。程序不能使用与关键字同名的标识符。标准C++有63个关键字,根据关键字的作用,可以将其分为数据类型关键字和流程控制关键字两大类。正确而恰当地使用关键字可以有效地提高程序的质量,起到事半功倍的效果。但如果不恰当地使用这些关键字,则可能会使程序存在某种程度的缺陷,甚至会给程序带来灾难性的后果。本章重点讨论C++的关键字, 以及关键字使用中的陷阱和注意事项,希望能对读者有所帮助。

尽可能多地使用 const

const可以说是C++中最为神奇的关键字。它的神奇之处在于:可以通过编译器指定语义上的约束,而不需要花费任何的代价。例如,你可以通过const关键字告诉编译器和其他程序员,你程序中的某个数值需保持恒定不变,不论何时只要你这么做了, 编译器就会协助你保证此约束不被破坏。

const关键字的用途是多种多样的。例如,在类的外部,可以定义全局作用域的常量,也可以通过添加static来定义文件、函数或程序块作用域的常量。对于指针,通过const可以定义指针是const、其所指向的数据是const或两者都是const。 例如:

char szGreeting[] ="Hello! My God!";
char *pszGreeting=szGreeting;// 非const 指针,非const 数据
const char* pszGreeting=szGreeting;//非 const 指针,const 数据
char *const pszGreeting= szGreeting;//const 指针,非 const 数据
const char *const pszGreeting=szGreeting;    //const 指针,const 数据

上述语法也许让你眩晕,但如果你仔细研究,就会发现这里面的规律。规律总结如下:

●如果const在*的左边,说明指针所指向的对象是常值;如果所指向的对象为常值,const在类型的前面和后面都一样。

●如果const在*的右边,说明指针是恒值。

●最复杂的是const同时出现在*的左右两侧,此时说明指针是恒值,指针所指向的对象也是恒值。

const关键字的功能不仅表现在变量定义方面,在函数声明、函数返回值及类成员函数方面也有着让我们惊讶的表现。

1.函数声明使用const

有些人喜欢把const放到类型的前面,有些人喜欢把const放到类型的后面,但有一点是肯定的,如果有*号必须放在*的前面。按照上面的总结,这两种声明其实并没什么本质的区别。如果你从事MFC开发,下面两个函数的声明也许你不会陌生:

void UpdateUI_1(const CWnd *pWnd);//向UpdateUI_1传入指向CWnd对象常量的指针void UpdateUI_2(CWnd const *pWnd);//UpdateUI_2声明和UpdateUI_1一样

上述两个声明,无论哪种声明都约束pWnd所指向的对象在整个函数执行过程中禁止修改。

2.函数返回值声明为const

让函数返回一个常量值,经常可以在不降低安全性和效率的前提下减少用户出错的概率。为了说明这个问题,我们先看下面的代码片段:

CRational {} //有理数类,支持有理数的加减乘除四则运算
CRational operator*(const rational& lhs,const rational&rhs);//有理数乘法运算
CRational a, b, c;
...
(a*b)=c;//对a*b的结果赋值,不符合逻辑,但可以通过编译

笔者不知道为何有些程序员会想到对两个数的运算结果直接赋值,但笔者却知道: 如果a、b和c是固定类型,这种做法显然是不合法的。但不幸的是,上述代码片段虽然不合法,但C++编译器却没有检测出来。明白了其中的问题,我们再看下面的代码片段:

CRational {} //有理数类,支持有理数的加减乘除四则运算
const CRational operator*(const rational& lhs,const rational&rhs); //有理数乘法运算
CRational a, b,c;
...
(a*b)=c;//对a*b的结果赋值,编译器报出编译错误

可以看出,声明operator*操作符重载函数的返回值为const可以避免对两个数的运算结果赋值问题。对程序员来说,对两个数的运算结果赋值是非常没道理的。声明operator*的返回值为const可以防止这种情况,所以这样做才是正确的。

小心陷阱

●一个好的用户自定义类型的特征是:它会避免那种没道理的、与固定类型不兼容的行为。

3.const成员函数

函数具有const属性,这是C++所特有的特征。将成员函数声明为const就是指明这个函数可以被const对象调用。

const 成员函数的优点:

●const成员函数可使得类的接口更加易于理解。

●const成员函数可以与const对象协同工作。这是高效编码十分重要的一个方面。

如果成员函数之间的区别仅仅为“是否是const的”,那么它们可被重载。很多人都忽略了这一点,但这是C++的重要特征之一。

说了这么多,现在我们讨论把一个成员函数声明为const到底有什么玄机?这里面有两个说法:按位恒定和逻辑恒定。

按位恒定坚持:当且仅当一个成员函数对所有的数据成员都不做出改动时,才需要将此函数声明为const。也就是说如果一个成员函数声明const的条件是:成员函数不对对象内部做任何修改。按位恒定的一个好处就是:它使得错误检查变得更轻松。 但不是一个成员函数声明了const,它就不会修改类对象的数据成员。下面这个例子就是这样,虽然成员函数声明了const属性,但它依然可以修改类对象的数据成员。这显然是有问题的。

class CHString  //自定义CHstring类,类似 STL中的 string类
{
public:
...
char& operator[](std::size_t position) const //定义CHstring类,[]中括号运算符
{
    return pText[position];
private:
    char*pText;
};

const CHString cctb("Hello");//声明对象常量
char*pc=&cctb[0];            //调用const 的operator[]

//从而得到一个指向cctb 中数据的指针
*pc=J;                      // cctb现在的值为Jello

于是逻辑恒定论便应运而生了。逻辑恒定论坚持:一个const的成员函数可能对其调用的对象内部做出改动,但是仅仅以客户端无法察觉的方式进行。利用可变的mutable数据成员可实现这一目标(mutable可以使非静态数据成员不受按位恒定规则的约束):

//字符串输出次数统计实现类,统计字符串被使用了多少次
class ClxTest
{
public:
    ClxTest();
    ~ClxTest();
    // 输出字符串
    void Output() const;
    // 获得字符串输出次数
    int GetOutputTimes() const;
    private:
    / 字符串输出次数
    mutable int m_iTimes;
};
//构造函数
ClxTest::ClxTest()
{
    m_iTimes=0;
} //析构函数
ClxTest::~ClxTest()
{
}
// 输出字符串
void ClxTest::Output() const
{
    cout<<"Output for test!"<<endl;
} m_iTimes++;
// 字符串输出次数
int ClxTest::GetOutputTimes() const
{
    return m_iTimes;
}
// 字符串输出测试
void OutputTest(const ClxTest& lx)
{
    cout<<lx.GetOutputTimes()<<endl;
    lx.Output();
    cout<<lx.GetOutputTimes()<<endl;
}

4.尽量用const常量替换#define常量定义

在C语言中定义一个int型常量,必须这样定义:

#define MAX_LENGTH

而C++则大可不必,因为这种实现存在很多陷阱。如#define只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意想不到的错误(边际效应)。

我们可以通过const实现常量定义。如上述定义可以用const定义为:

const int MAX_LENGTH = 100;

除了上述陷阱以外,从汇编的角度来看const定义常量,只是给出了对应的内存地址,而不是像#define一样给出的是立即数。const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝,所以使用const常量可以节省内存。

请谨记

●将某些东西声明为const可帮助编译器侦测出错误用法。const可用于任何作用域的对象、函数形参、函数返回值、成员函数本体等。

●尽量用const替换#define, 因为这种替换好处多多。

第十九章:尽可能多地使用 const,了解C/C++基本语言特性关键字【免费技术教程】
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

常见问题

  • 如何安装和激活?

    每款软件会附带有安装教程,您打开安装包一目了然

  • 程序是否已损坏?文件损坏?还是其他错误?

    有错误问题,请您参考:https://www.xxx.com/error

  • 如何更新?正式激活后会发生什么情况?

    除非安装说明中另有说明,否则官方更新可能会导致无法激活。 要从本网站更新软件,您需要在此处下载此软件的新版本(如果可用),并将其安装在计算机上安装的版本之上(替换)。在这种情况下,您将保存此软件的激活和设置。

  • 如何下载?链接不起作用?

    我们使用百度网盘,132云盘和微软网盘,除了百度网盘,其他两款不限速,如果链接失效,请您联系客服处理

  • 已发布更新。我什么时候升级我的版本?

    所有软件如有更新,我们第一时间推送,视自己情况更新使用

  • 如何更改语言?

    打开“系统偏好设置”->“通用>语言和地区”->应用程序-“+”。 选择应用和语言。此方法适用于大多数应用程序。 Adobe 产品中的语言通常是在产品本身的安装阶段选择的。 游戏中的语言通常会在游戏本身的设置中发生变化。

  • 如何删除软件?

    有很多选择。最简单的方法是使用特殊的实用程序来卸载应用程序,例如App Cleaner Uninstaller 要删除 Adobe 产品,请使用 Creative Cloud Cleaner Tool

  • 需要远程帮助吗?

    网站已开通永久会员的可享受免费远程,如果非永久会员,远程安装另外收费

给TA打赏
共{{data.count}}人
人已打赏
Windows教程技术教程

永久禁止自动更新微软edge浏览器升级,频繁无响应卡死受影响版本122.0.2365.52

2024-3-1 10:24:41

技术教程

谷歌浏览器 Google Chrome 免费下载及安装保姆级技术教程

2024-3-2 21:01:35

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧