const的用法,特别是用在函数后面

本文详细介绍了 C++ 中 const 的多种用途,包括修饰函数参数、返回值及成员函数等,强调其对提高程序健壮性和效率的重要性。
<span style="line-height: 0.47cm;  font-family: FangSong_GB2312;"><strong></strong></span>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">在普通的非 </span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数中,</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">的类型是一个指向类类型的 </span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">指针</span><span style="font-family: FangSong_GB2312;">。可以改变</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">所指向的值,但不能改变 </span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">所保存的地址。
在 </span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数中,</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">的类型是一个指向 </span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">类类型对象的 </span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">指针。既不能改变 </span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">所指向的对象,也不能改变 </span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">所保存的地址。</span></span></strong>
<strong><span style="font-family: FangSong_GB2312;"><span style="font-size:14px;"></span></span></strong>
<div style="text-align: left;"><span style="font-family:FangSong_GB2312;font-size:14px;"><span style="line-height: 17.7637786865234px; white-space: pre-wrap;"><strong>
</strong></span></span></div>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">
</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">看到</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">关键字,</span><span style="font-family: FangSong_GB2312;">C++</span><span style="font-family: FangSong_GB2312;">程序员首先想到的可能是</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">常量。这可不是良好的条件反射。如果只知道用</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">定义常量,那么相当于把火药仅用于制作鞭炮。</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">更大的魅力是它可以修饰函数的参数、返回值,甚至函数的定义体。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">const </span><span style="font-family: FangSong_GB2312;">是</span><span style="font-family: FangSong_GB2312;">constant</span><span style="font-family: FangSong_GB2312;">的缩写,“恒定不变”的意思。被</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多</span><span style="font-family: FangSong_GB2312;">C++</span><span style="font-family: FangSong_GB2312;">程序设计书籍建议:“</span><span style="font-family: FangSong_GB2312;">Useconst whenever you need”</span><span style="font-family: FangSong_GB2312;">。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">
</span></span></strong>
<div style="text-align: left; line-height: 0.47cm; white-space: pre-wrap;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>     1.</strong></span><span style=" line-height: 0.47cm; text-indent: 0.74cm; font-family: FangSong_GB2312;"><strong><span style="background: rgb(255, 255, 0);">用const</span><span style="background: rgb(255, 255, 0);">修饰函数的参数</span></strong></span></div><div style="text-align: left;"><span style="font-family:FangSong_GB2312;font-size:14px;"><span style="line-height: 17.7637786865234px; white-space: pre-wrap;"><strong>
</strong></span></span></div>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;"><span style="background: rgb(255, 255, 0);">
</span></span></span></strong>
<span style="font-weight: bold;"><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰,否则该参数将失去输出功能。<span style="font-family: 'AR PL UMing HK', serif;"><span style="background: rgb(0, 255, 255);">const</span></span><span style="background: rgb(0, 255, 255);">只能修饰输入参数:</span></span></span></span>
<strong><span style="font-family: FangSong_GB2312;"><u><span style="font-size:14px;">如果输入参数采用“指针传递”,那么加const修饰可以防止意外地改动该指针,起到保护作用。</span></u></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">例如</span><span style="font-family: FangSong_GB2312;">StringCopy</span><span style="font-family: FangSong_GB2312;">函数:</span></span></strong>
<strong><span style="font-family: FangSong_GB2312;"><span style="font-size:14px;">void StringCopy(char*strDestination, const char *strSource);</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">其中</span><span style="font-family: FangSong_GB2312;">strSource</span><span style="font-family: FangSong_GB2312;">是输入参数,</span><span style="font-family: FangSong_GB2312;">strDestination</span><span style="font-family: FangSong_GB2312;">是输出参数。给</span><span style="font-family: FangSong_GB2312;">strSource</span><span style="font-family: FangSong_GB2312;">加上</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰后,<u>如果函数体内的语句试图改动strSource的内容,编译器将指出错误。</u></span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">例如不要将函数</span><span style="font-family: FangSong_GB2312;">voidFunc1(int x) </span><span style="font-family: FangSong_GB2312;">写成</span><span style="font-family: FangSong_GB2312;">voidFunc1(const int x)</span><span style="font-family: FangSong_GB2312;">。同理不要将函数</span><span style="font-family: FangSong_GB2312;">voidFunc2(A a) </span><span style="font-family: FangSong_GB2312;">写成</span><span style="font-family: FangSong_GB2312;">voidFunc2(const A a)</span><span style="font-family: FangSong_GB2312;">。其中</span><span style="font-family: FangSong_GB2312;">A</span><span style="font-family: FangSong_GB2312;">为用户自定义的数据类型。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">对于非内部数据类型的参数而言,象</span><span style="font-family: FangSong_GB2312;">voidFunc(A a) </span><span style="font-family: FangSong_GB2312;">这样声明的函数注定效率比较底。因为函数体内将产生</span><span style="font-family: FangSong_GB2312;">A</span><span style="font-family: FangSong_GB2312;">类型的临时对象用于复制参数</span><span style="font-family: FangSong_GB2312;">a</span><span style="font-family: FangSong_GB2312;">,而临时对象的构造、复制、析构过程都将消耗时间。</span></span></strong>
<strong><span style="font-family: FangSong_GB2312;"><u><span style="font-size:14px;">为了提高效率,可以将函数声明改为voidFunc(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象。但是函数voidFunc(A &a) 存在一个缺点:</span></u></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">“</span><span style="font-family: FangSong_GB2312;">引用传递”有可能改变参数</span><span style="font-family: FangSong_GB2312;">a</span><span style="font-family: FangSong_GB2312;">,这是我们不期望的。解决这个问题很容易,加</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰即可,因此函数最终成为</span><span style="font-family: FangSong_GB2312;">voidFunc(const A &a)</span><span style="font-family: FangSong_GB2312;">。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">以此类推,是否应将</span><span style="font-family: FangSong_GB2312;">voidFunc(int x) </span><span style="font-family: FangSong_GB2312;">改写为</span><span style="font-family: FangSong_GB2312;">voidFunc(const int&x)</span><span style="font-family: FangSong_GB2312;">,以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">问题是如此的缠绵,我只好将“</span><span style="font-family: FangSong_GB2312;">const&”</span><span style="font-family: FangSong_GB2312;">修饰输入参数的用法总结一下。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312; color: rgb(255, 0, 0);">对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const</span><span style="font-family: FangSong_GB2312; color: rgb(255, 0, 0);">引用传递”,目的是提高效率</span><span style="font-family: FangSong_GB2312;">。例如将</span><span style="font-family: FangSong_GB2312;">voidFunc(A a) </span><span style="font-family: FangSong_GB2312;">改为</span><span style="font-family: FangSong_GB2312;">voidFunc(const A &a)</span><span style="font-family: FangSong_GB2312;">。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">对于内部数据类型的输入参数,不要将“值传递”的方式改为“</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如</span><span style="font-family: FangSong_GB2312;">voidFunc(int x) </span><span style="font-family: FangSong_GB2312;">不应该改为</span><span style="font-family: FangSong_GB2312;">voidFunc(const int &x)</span><span style="font-family: FangSong_GB2312;">。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">
</span></span></strong>
<div style="text-align: left; line-height: 0.47cm; white-space: pre-wrap;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>     2</strong></span><span style=" line-height: 0.47cm; text-indent: 0.74cm; font-family: FangSong_GB2312;"><strong><span style="background: rgb(255, 255, 0);">用const</span><span style="background: rgb(255, 255, 0);">修饰函数的返回值</span></strong></span></div><div style="text-align: left;"><span style="font-family:FangSong_GB2312;font-size:14px;"><span style="line-height: 17.7637786865234px; white-space: pre-wrap;"><strong>
</strong></span></span></div>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;"><span style="background: rgb(255, 255, 0);">
</span></span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如果给以“指针传递”方式的函数返回值加</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰,那么函数返回值(即指针)的内容不能被修改,<u>该返回值只能被赋给加const修饰的同类型指针。例如函数
</u></span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">constchar * GetString(void);</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如下语句将出现编译错误:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">char*str = GetString();</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">正确的用法是</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">constchar *str =GetString();</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰没有任何价值。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">例如不要把函数</span><span style="font-family: FangSong_GB2312;">intGetInt(void) </span><span style="font-family: FangSong_GB2312;">写成</span><span style="font-family: FangSong_GB2312;">constint GetInt(void)</span><span style="font-family: FangSong_GB2312;">。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">同理不要把函数</span><span style="font-family: FangSong_GB2312;">AGetA(void) </span><span style="font-family: FangSong_GB2312;">写成</span><span style="font-family: FangSong_GB2312;">constA GetA(void)</span><span style="font-family: FangSong_GB2312;">,其中</span><span style="font-family: FangSong_GB2312;">A</span><span style="font-family: FangSong_GB2312;">为用户自定义的数据类型。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如果返回值不是内部数据类型,将函数</span><span style="font-family: FangSong_GB2312;">AGetA(void) </span><span style="font-family: FangSong_GB2312;">改写为</span><span style="font-family: FangSong_GB2312;">constA &GetA(void)</span><span style="font-family: FangSong_GB2312;">的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">例如:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">classA</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">{</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">A & operate = (const A &other); // </span><span style="font-family: FangSong_GB2312;">赋值函数</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">};</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">Aa, b, c; // a, b, c </span><span style="font-family: FangSong_GB2312;">为</span><span style="font-family: FangSong_GB2312;">A</span><span style="font-family: FangSong_GB2312;">的对象</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">
</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">a= b = c; // </span><span style="font-family: FangSong_GB2312;">正常的链式赋值</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">(a= b) = c; // </span><span style="font-family: FangSong_GB2312;">不正常的链式赋值,但合法</span></span></strong>
<div style="text-align: left; line-height: 0.47cm; white-space: pre-wrap;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>如果将赋值函数的返回值加</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>修饰,那么该返回值的内容不允许被改动。上例中,语句</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>a= b = c </strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>仍然正确,但是语句</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>(a= b) = c </strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>则是非法的。</strong></span></div><div style="text-align: left;"><span style="font-family:AR PL UMing HK, serif;font-size:14px;"><span style="line-height: 17.7637786865234px; white-space: pre-wrap;"><strong>
</strong></span></span></div><span style="font-size:14px;font-weight: bold; line-height: 0.47cm; white-space: pre-wrap;"></span><div style="text-align: left;"><span style="line-height: 0.47cm; font-family: 'AR PL UMing HK', serif;"><span style="background: rgb(255, 255, 0);">3const </span></span><span style="font-family: FangSong_GB2312; line-height: 0.47cm; background: rgb(255, 255, 0);">成员函数</span></div>
<span style="font-weight: bold;"><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;"><span style="font-family: 'AR PL UMing HK', serif;"><span style="background: rgb(255, 255, 0);">
</span></span></span></span></span>
<span style="font-weight: bold;"><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;"><span style="font-family: 'AR PL UMing HK', serif;"><span style="background: rgb(255, 255, 0);">3const </span></span><span style="background: rgb(255, 255, 0);">成员函数</span></span></span></span>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">
</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312; color: rgb(255, 0, 0);">任何不会修改数据成员的函数都应该声明为const</span><span style="font-family: FangSong_GB2312; color: rgb(255, 0, 0);">类型。</span><span style="font-family: FangSong_GB2312;">如果在编写</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数时,不慎修改了数据成员,或者调用了其它非</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数,编译器将指出错误,这无疑会提高程序的健壮性。以下程序中,类</span><span style="font-family: FangSong_GB2312;">stack</span><span style="font-family: FangSong_GB2312;">的成员函数</span><span style="font-family: FangSong_GB2312;">GetCount</span><span style="font-family: FangSong_GB2312;">仅用于计数,从逻辑上讲</span><span style="font-family: FangSong_GB2312;">GetCount</span><span style="font-family: FangSong_GB2312;">应当为</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">函数。编译器将指出</span><span style="font-family: FangSong_GB2312;">GetCount</span><span style="font-family: FangSong_GB2312;">函数中的错误。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">classStack</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">{</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">public:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">void Push(int elem);</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">int Pop(void);</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">intGetCount(void) const; // const </span><span style="font-family: FangSong_GB2312;">成员函数</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">private:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">intm_num;</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">int m_data[100];</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">};</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">int Stack::GetCount(void)const</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">{</span></span></strong>
<div style="text-align: left;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>++ m_num; // </strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>编译错误,企图修改数据成员</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>m_num</strong></span></div><strong></strong><div style="text-align: left;"><span style="font-family: FangSong_GB2312;font-size:14px; line-height: 0.47cm;">Pop();// </span></div>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">Pop();// </span><span style="font-family: FangSong_GB2312;">编译错误,企图调用非</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">函数</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">returnm_num;</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">}</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">const </span><span style="font-family: FangSong_GB2312;">成员函数的声明看起来怪怪的:</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">关于</span><span style="font-family: FangSong_GB2312;">Const</span><span style="font-family: FangSong_GB2312;">函数的几点规则:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">
</span></span></strong>
<div style="text-align: left;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>a.const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>对象只能访问</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>成员函数</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>,</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>而非</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>对象可以访问任意的成员函数</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>,</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>包括</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>成员函数</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>.</strong></span></div><strong></strong><div style="text-align: left;"><span style="font-family: FangSong_GB2312;font-size:14px; line-height: 0.47cm;">b.const</span></div>
<div style="text-align: left;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>b.const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>对象的成员是不可修改的</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>,</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>然而</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>对象通过指针维护的对象却是可以修改的</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>.</strong></span></div><strong></strong><div style="text-align: left;"><span style="font-family: FangSong_GB2312;font-size:14px; line-height: 0.47cm;">c.const</span></div>
<div style="text-align: left;"><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>c.const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>成员函数不可以修改对象的数据</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>,</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>不管对象是否具有</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>const</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>性质</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>.</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>它在编译时</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>,</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>以是否修改成员数据为依据</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>,</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>进行检查</strong></span><span style=" line-height: 0.47cm; font-family: FangSong_GB2312;"><strong>.</strong></span></div><strong></strong><div style="text-align: left;"><span style="font-family: FangSong_GB2312;font-size:14px; line-height: 0.47cm;">e.</span></div>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">e.</span><span style="font-family: FangSong_GB2312;">然而加上</span><span style="font-family: FangSong_GB2312;">mutable</span><span style="font-family: FangSong_GB2312;">修饰符的数据成员</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">对于任何情况下通过任何手段都可修改</span><span style="font-family: FangSong_GB2312;">,</span><span style="font-family: FangSong_GB2312;">自然此时的</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">成员函数是可以修改它的</span></span></strong>
<strong><span style="font-family: FangSong_GB2312;"><span style="font-size:14px;"> </span></span></strong>
<strong><span style="font-family: FangSong_GB2312;"><span style="font-size:14px;"> </span></span></strong>
<strong><span style="font-family: FangSong_GB2312;"><span style="font-size:14px;">补充:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">标题</span><span style="font-family: FangSong_GB2312;">:const</span><span style="font-family: FangSong_GB2312;">放在后面有什么意思?</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">--------------------------------------------------------------------------------</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">一个函数</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">AcGePoint3dstartPoint() const;</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">放在后面跟前面有区别么</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">==></span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">准确的说</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">是修饰</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">指向的对象的</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">譬如,我们定义了</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">classA{</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">public:</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">f(int);</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">};</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">这里</span><span style="font-family: FangSong_GB2312;">f</span><span style="font-family: FangSong_GB2312;">函数其实有两个参数,第一个是</span><span style="font-family: FangSong_GB2312;">A*const this, </span><span style="font-family: FangSong_GB2312;">另一个才是</span><span style="font-family: FangSong_GB2312;">int</span><span style="font-family: FangSong_GB2312;">类型的参数</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">如果我们不想</span><span style="font-family: FangSong_GB2312;">f</span><span style="font-family: FangSong_GB2312;">函数改变参数的值,可以把函数原型改为</span><span style="font-family: FangSong_GB2312;">f(constint),</span><span style="font-family: FangSong_GB2312;">但如果我们不允许</span><span style="font-family: FangSong_GB2312;">f</span><span style="font-family: FangSong_GB2312;">改变</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">指向的对象呢?因为</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">是隐含参数,</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">没法直接修饰它,就加在函数的后面了,表示</span><span style="font-family: FangSong_GB2312;">this</span><span style="font-family: FangSong_GB2312;">的类型是</span><span style="font-family: FangSong_GB2312;">constA *constthis</span><span style="font-family: FangSong_GB2312;">。</span></span></strong>
<strong><span style="font-size:14px;"><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">修饰</span><span style="font-family: FangSong_GB2312;">*this</span><span style="font-family: FangSong_GB2312;">是本质,至于说“表示该成员函数不会修改类的数据。否则会编译报错”之类的说法只是一个现象,根源就是因为</span><span style="font-family: FangSong_GB2312;">*this</span><span style="font-family: FangSong_GB2312;">是</span><span style="font-family: FangSong_GB2312;">const</span><span style="font-family: FangSong_GB2312;">类型的</span></span></strong>

<think> 首先,用户的问题是:“请问C++中函数前面加const函数后面const的区别”。 根据系统级指令,我需要: 1. 所有行内数学表达式使用$...$格式。 2. 独立公式使用$$...$$格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识。 此外,用户提供了多个引用,我需要参考这些引用来回答。 关键点总结用户的引用: - 引用[1]:函数后面const表示成员函数const,不能修改类的成员变量,除非有mutable修饰。它可以被const和非const对象调用。 - 引用[2]:类似[1],强调非静态成员函数后加const。 - 引用[3]:函数后加const声明为只读函数,提高可读性和健壮性。 - 引用[4]:函数后加const允许在const对象上调用。 - 引用[5]:const成员函数不能修改成员变量。 用户的问题是关于函数前面加const后面const的区别: - 函数后面const:针对成员函数,表示该函数不会修改类的成员变量(this指针被视为const)。 - 函数前面加const:通常表示函数的返回值是const类型。 用户引用中也提到了:引用[1]说“前面使用const 表示返回值为const 后面const表示函数不可以修改class的成员”。 所以,区别是: - **函数前面加const**:应用于函数的返回类型。这意味着函数返回一个const值或const引用。例如,`const int getValue();` 返回一个const int。 - **函数后面const**:仅用于成员函数的声明或定义后。表示该函数const成员函数,不会修改对象的状态(this指针是const)。 在回答中,我需要结构化: 1. 解释函数前面加const:修改返回类型。 2. 解释函数后面const:修改成员函数常量性。 3. 比较区别。 4. 给出例子。 5. 生成相关问题。 使用中文回答。 确保LaTeX语法正确:由于这是关于C++的,可能没有太多数学表达式,但如果有变量或类型,可以用$...$表示。 例如,提到`const int getValue();`,可以写成行内代码或简单描述。 系统指令说数学表达式用$...$,但对于代码,可能更适合用代码块或直接写。指令说“包括变量、不等式、方程等”,所以对于代码中的表达式,如返回类型,可以用$...$。 为了简单,我可以直接在文本中写代码,或者用` `表示行内代码。 在回答中,自然地添加引用标识:[^1], [^2]等。 生成相关问题:在最后添加“§§相关问题§§”部分。 结构回答: - 先简要概述。 - 详细解释函数前面加const。 - 详细解释函数后面const。 - 比较区别。 - 添加例子。 - 生成相关问题。 引用来源:用户提供了引用[1]到[5],我需要引用它们。 例如: - 函数后面const用于成员函数,使其成为const成员函数,不能修改成员变量[^1]。 - 函数前面加const表示返回值为const[^1]。 现在,回答内容: **函数前面加const的区别:** - 当const关键字出现在函数声明前时,它修饰的是函数的返回类型。这意味着函数返回的值是const的,不能被修改。 - 例如:`const int getValue();` 返回一个const int,调用后不能修改返回值。 - 这主要用于防止返回值被意外修改。 **函数后面const的区别:** - const关键字出现在成员函数声明后,表示该函数是一个const成员函数。 - 它承诺不会修改类的成员变量(除非是mutable成员)[^5]。 - 它可以被const对象调用[^4]。 - 非const成员函数不能被const对象调用。 - 提高代码的可读性和可靠性[^3]。 **关键区别:** - 位置不同:前面修饰返回类型,后面修饰成员函数常量性。 - 适用对象:前面加const适用于任何函数(成员或非成员),修饰返回类型;后面const只适用于非静态成员函数,修饰函数本身的常量性。 例子: - 函数前面加const:`const char* getName();` 返回一个指向const char的指针。 - 函数后面const:`int getAge() const;` 在类成员函数中,表示getAge不会修改对象状态。 生成相关问题: 1. 什么时候应该在成员函数后加const? 2. 返回const值的好处是什么? 3. const对象如何调用成员函数? 4. mutable关键字在const成员函数中的作用是什么? 确保回答真实可靠,基于C++标准。 </think> ### C++中函数前面加const函数后面const的区别 在C++中,const关键字的位置(函数前面或后面)具有完全不同的语义和作用范围。理解这两种用法的区别对于编写健壮、可读性强的代码至关重要。以下是详细的解释和对比,基于您提供的引用内容。 #### 1. **函数前面加const(修饰返回类型)** - **含义**:当const关键字出现在函数声明的前面时,它修饰的是函数的**返回类型**。这表示函数返回的值是const的,不能被修改。 - **作用**: - 防止返回值被意外修改,增强代码的安全性。 - 适用于任何函数(包括成员函数和非成员函数),主要针对返回值本身的常量性。 - 例如,`const int getValue();` 返回一个const int,调用该函数后,返回值不可修改(如试图赋值会引发编译错误)。 - **示例**: ```cpp const char* getName() { // 返回指向const char的指针,指针内容不可修改 return "Constant"; } ``` - 在这个例子中,返回的字符串不能被修改(如`getName()[0] = 'a';` 会编译失败)。 - **优点**:提高代码的封装性,避免返回值被误用[^1][^3]。 #### 2. **函数后面const(修饰成员函数常量性)** - **含义**:当const关键字出现在成员函数声明的后面时,它表示该函数是一个**const成员函数**。 - **作用**: - 该函数不会修改类的任何非mutable成员变量(this指针被视为const)。 - 它可以被const对象和非const对象调用,而非const成员函数只能被非const对象调用[^1][^4]。 - 如果函数内部试图修改成员变量,编译器会报错(除非变量被mutable修饰)[^5]。 - 仅适用于非静态成员函数;静态成员函数或非成员函数后加const会导致编译错误[^2]。 - **示例**: ```cpp class MyClass { int value; public: int getValue() const { // const成员函数 // value = 42; // 错误:不能修改成员变量 return value; // 只能读取 } }; ``` - 在这个例子中,`getValue() const` 可以被const对象调用(如`const MyClass obj; obj.getValue();`)。 - **优点**:提高程序的可读性和可靠性,便于const对象的使用,并帮助编译器检测非法修改[^1][^3][^5]。 #### 3. **关键区别总结** 下表对比了两种const用法的主要差异: | 特性 | 函数前面加const | 函数后面const | |--------------------|----------------------------------|-------------------------------------| | **位置** | 函数声明前(修饰返回类型) | 成员函数声明后(修饰函数常量性) | | **作用对象** | 函数的返回值 | 成员函数的this指针和对象状态 | | **适用函数类型** | 任何函数(成员或非成员) | 仅非静态成员函数 | | **常量性保证** | 返回值不可修改 | 函数不修改成员变量(除非mutable) | | **调用对象限制** | 无(与对象常量性无关) | const对象可调用;非const对象也可调用 | | **编译错误场景** | 修改返回值时出错 | 修改成员变量或调用非const函数时出错 | | **常见用途** | 返回常量数据(如const指针) | 访问器函数(getter)或只读操作 | - **核心区别**:函数前面加const控制**返回值的可修改性**,而函数后面const控制**成员函数对对象状态的修改权限**。两者互不影响,可以同时使用(例如`const int getValue() const;` 表示返回const值且函数本身为const)[^1][^3][^5]。 #### 4. **示例对比** ```cpp #include <iostream> class Example { int data = 10; mutable int counter = 0; // mutable成员可在const函数中修改 public: // 函数前面加const:返回const int const int getConstResult() { return data; // 返回值不可修改 } // 函数后面constconst成员函数 int readData() const { counter++; // 正确:mutable成员可修改 // data = 20; // 错误:不能修改非mutable成员 return data; } // 组合使用:返回const值且函数const const int getData() const { return data; } }; int main() { Example obj; const Example constObj; // 函数前面加const示例 // const int result = obj.getConstResult(); // result = 5; // 错误:返回值是const,不可修改 // 函数后面const示例 int value = constObj.readData(); // 正确:const对象可调用const函数 // constObj.getConstResult(); // 可能错误:非const函数不能被const对象调用(除非函数const) } ``` 在这个例子中: - `getConstResult()`前面加const,确保返回值不可修改。 - `readData()`后面const,允许const对象调用,且不修改对象状态。 - `getData()`同时使用两者,提供双重保护[^1][^3][^5]。 #### 为什么重要? - 使用const成员函数(后加const)能更好地支持const对象,避免意外修改对象状态,提高代码健壮性[^3][^4]。 - 返回const值(前加const)则用于API设计,强制客户端代码不修改返回的数据[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值