C++成員函數(shù)中const的使用詳解
const 在C++中是一個很重要的關(guān)鍵字,其不光可以用來修飾變量,還可以放在函數(shù)定義中,這里整理了其在函數(shù)中的三個用法。
修飾入?yún)?/h2>
首先我們要明白在C++中調(diào)用函數(shù)時存在兩種方法,即傳遞值和傳遞引用。
值傳遞
值傳遞時,調(diào)用函數(shù)時會創(chuàng)建入?yún)⒌目截?,函?shù)中的操作不會對原值進(jìn)行修改,因此這種方式中不需要使用 const 來修飾入?yún)?,因?yàn)槠渲皇菍截惖呐R時對象進(jìn)行操作。
址傳遞
傳遞地址時函數(shù)中的操作實(shí)際上是直接對原來的值進(jìn)行修改,因此我們這里可以使用 const 修飾入?yún)ⅰ?/p>
const修飾入?yún)?/h3>
當(dāng)const修飾函數(shù)入?yún)r表示該參數(shù)不能被修改,這個是最好理解的,比如一個函數(shù)的功能是拷貝,那么入?yún)⒅械脑次募紩?const 修飾。
void A::show(const int *b) {
cout << "show const";
// error: read-only variable is not assignable
// *b = 2;
cout << b << endl;
}
接下來我們要關(guān)注的是這里 const 對于函數(shù)重載的作用,這里給出結(jié)論,歡迎大家討論,對應(yīng)按值傳遞的函數(shù)來說 const 不會有重載的效果,但是傳遞指針和引用是會有重載的效果。
void A::show(const int b) // void A::show(int b) // error class member cannot be redeclared void display(int *num); // overload void display(const int *num); // overload void fun(A &a); // overload void fun(const A &a); // overload
函數(shù)重載的關(guān)鍵是函數(shù)的參數(shù)列表——即函數(shù)特征標(biāo)(function signature)。如果兩個函數(shù)的參數(shù)數(shù)目和類型相同,并且參數(shù)的排列順序也相同,則他們的特征標(biāo)相同,而變量名是無關(guān)緊要的。
總結(jié)一下注意點(diǎn):
- 如果輸入?yún)?shù)采用“值傳遞”,**由于函數(shù)將自動產(chǎn)生臨時變量用于復(fù)制該參數(shù),該輸入?yún)?shù)本來就無需保護(hù),所以不要加 const 修飾。**例如不要將函數(shù)
void Func1(int x)寫成void Func1(const int x)。 - 如果參數(shù)作為輸出參數(shù),不論它是什么數(shù)據(jù)類型,也不論它采用“指針傳遞”還是“引用傳遞”,都不能加 const 修飾,否則該參數(shù)將失去輸出功能(因?yàn)橛?const 修飾之后,不能改變他的值)。
- 如果參數(shù)作為輸入?yún)?shù),可以防止數(shù)據(jù)被改變,起到保護(hù)作用,增加程序的健壯性,建議是能加const盡量加上
上述測試代碼如下:
#include <iostream>
using namespace std;
class A {
private:
int a;
public:
A(int a) {
this->a = a;
}
void show(int b);
// error redeclared
// void show(const int b);
void display(int *num); // ok
void display(const int *num); // ok
void fun(A &a);
void fun(const A &a);
void happy(int * h);
void hour(const int * h);
};
void A::show(int b) {
cout << "show: " << b << endl;
}
void A::display(int *num) {
cout << "display:" << *num << endl;
}
void A::display(const int *num) {
cout << "const display:" << *num << endl;
}
void A::fun(A &obj) {
cout << "fun: " << obj.a << endl;
}
void A::fun(const A &obj) {
cout << "const fun: " << obj.a << endl;
}
void A::happy(int *h) {
cout << "happy:" << *h << endl;
}
void A::hour(const int *h) {
cout << "const hour:" << *h << endl;
}
int main() {
A a(1);
const A a2(11);
int b1 = 2;
const int b2 = 3;
// test overload
a.show(b1);
a.show(b2);
a.display(&b1);
a.display(&b2);
a.fun(a);
a.fun(a2);
// test const
a.happy(&b1);
// a.happy(&b2); // error cannot initialize a parameter of type 'int *' with an rvalue of type 'const int *'
a.hour(&b1);
a.hour(&b2);
return 0;
}
// ouptut
show: 2
show: 3
display:2
const display:3
fun: 1
const fun: 11
happy:2
const hour:2
const hour:3
修飾返回值
const 修飾返回值時,表示返回值不能被修改。需要注意的是如果函數(shù)返回值采用“值傳遞方式”,由于函數(shù)會把返回值復(fù)制到外部臨時的存儲單元中,加 const 修飾沒有任何價值。如果返回的是引用或指針,表示不能修改指向的數(shù)據(jù)。
一般用得多的是返回值是引用的函數(shù), 可以肯定的是這個引用必然不是臨時對象的引用, 因此一定是成員變量或者是函數(shù)參數(shù), 所以在返回的時候?yàn)榱吮苊馄涑蔀樽笾当恍薷模托枰由蟘onst關(guān)鍵字來修飾。
我們可以看如下代碼示例:
#include <iostream>
using namespace std;
class Alice {
private:
int a;
public:
Alice(int a): a(a) {}
int get_a() {return a;}
const int* get_const_ptr() {return &a;}
int* get_ptr() {return &a;}
};
int main() {
Alice alice(1);
int a1 = alice.get_a(); // ok
cout << a1 << endl;
const int a2 = alice.get_a(); // ok
cout << a2 << endl;
// error cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'
// int* b1 = alice.get_const_ptr();
const int* b2 = alice.get_const_ptr(); // ok
cout << *b2 << endl; // ok
// *b2 = 3; // error read-only variable is not assignable
*(alice.get_ptr()) = 3;
cout << alice.get_a() << endl; // 3
return 0;
}
修飾函數(shù)
const 也可以用來放在函數(shù)末尾,用來修飾成員函數(shù),表明其是一個常成員函數(shù),這個對于初次接觸C++的同學(xué)來說會有點(diǎn)陌生,不過這也是C++中嚴(yán)謹(jǐn)?shù)牡胤健O瓤创a示例,學(xué)習(xí)任何編程技術(shù)都一定要寫對應(yīng)的代碼,把它跑起來并分析結(jié)果才算是真正學(xué)會了,不會你只是知道了這個知識點(diǎn),只知其然而不知其所以然。紙上得來終覺淺,絕知此事要躬行,這里的要躬行指的就是寫代碼。
首先來看如下的代碼
class Alice {
private:
int a;
public:
Alice(int a): a(a) {}
void show();
};
void Alice::show() {
cout << "hello Alice" << endl;
}
int main() {
const Alice a(1);
// error: 'this' argument to member function 'show' has type 'const Alice', but function is not marked const
// a.show();
return 0;
}
上述代碼會報錯,因?yàn)?nbsp;show() 方法不是常成員函數(shù),而 a 是常對象。本質(zhì)上,成員函數(shù)中都有一個隱含的入?yún)?nbsp;this, 這個 this指的就是調(diào)用該方法的對象,而如果在函數(shù)的后面加上 const,那么這個 const 實(shí)際上修飾的就是這個 this。也就是說函數(shù)后加上了 const,表明這個函數(shù)不會改變調(diào)用者對象。
這里借用侯捷老師的圖片

上面圖片表明,在正常情況下:
- non-const對象可以調(diào)用const 或者 non-const 成員函數(shù)
- const 對象 只可以調(diào)用 const 成員函數(shù)
補(bǔ)充一點(diǎn),**如果成員函數(shù)同時具有 const 和 non-const 兩個版本的話, const 對象只能調(diào)用const成員函數(shù), non-const 對象只能調(diào)用 non-const 成員函數(shù)。**如以下代碼示例
#include <iostream>
using namespace std;
class R {
public:
R(int r1, int r2) {
a = r1;
b = r2;
}
void print();
void print() const;
private:
int a;
int b;
};
void R::print() {
cout << "normal print" << endl;
cout << a << ", " << b << endl;
}
void R::print() const {
cout << "const print" << endl;
cout << a << ", " << b << endl;
}
int main() {
R a(5, 3);
a.print();
const R b(6 ,6);
b.print();
return 0;
}
// output
normal print
5, 3
const print
6, 6
這里也是建議能加 const 的時候就加。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++ ffmpeg硬件解碼的實(shí)現(xiàn)方法
這篇文章主要介紹了C++ ffmpeg硬件解碼的實(shí)現(xiàn),對FFmpeg多媒體解決方案中的視頻編解碼流程進(jìn)行研究。為嵌入式多媒體開發(fā)提供參考,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
C語言實(shí)現(xiàn)帶頭雙向循環(huán)鏈表的接口
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)帶頭雙向循環(huán)鏈表的接口,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
使用?Visual?Studio?2022?開發(fā)?Linux?C++?應(yīng)用程序的過程詳解
Visual?Studio?2022?引入了用于?Linux?C++?開發(fā)的本機(jī)?WSL2?工具集,可以構(gòu)建和調(diào)試?Linux?C++?代碼,并提供了非常好的?Linux?文件系統(tǒng)性能、GUI?支持和完整的系統(tǒng)調(diào)用兼容性,這篇文章主要介紹了使用Visual?Studio?2022?開發(fā)?Linux?C++?應(yīng)用程序,需要的朋友可以參考下2021-11-11
VSCode下.json文件的編寫之(1) linux/g++ (2).json中參數(shù)與預(yù)定義變量的意義解釋
這篇文章主要介紹了VSCode下.json文件的編寫之(1) linux/g++ (2).json中參數(shù)與預(yù)定義變量的意義解釋,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03

