cpp 函數參數使用引用和const引用的區別(如string和const string&)

在c++中,&代表引用傳遞,跟指針的作用是一致的,只不過語法上做了一點點修改。
c++中函數參數如果是類對象一般使用&來修飾,從而避免不必要的構造和析構。
例如

class A{ };
void func(A&) { }

使用A&可以避免調用 A(A&) 來創建臨時對象和 ~A() 來銷燬臨時對象。

看下面代碼

void func(string& ) { }

int main() {
    func("asdfasdf");
}

如果直接編譯的話會出現 no matching function for call to 'myclass::myclass(const char [9])' 的錯誤信息。
如果把函數參數改爲 const string& 就可以編譯通過。

技巧:重載函數

void func(string& ) { cout << "1" << endl; } // func函數1 
void func(const string& ) { cout << "2" << endl; }  // func函數2 

int main() {
	string s("abcd");
	func(s); //調用func函數1 
    func("asdfasdf"); //調用func函數2 
}

運行結果分別輸出1,2
這樣重載函數的好處是外部對象調用時不需要構造string對象,調用起來比較的方便。

如何理解

編寫如下測試代碼

class A{
public:
	A() { cout << "A()" << endl; }
	A(const char*) { cout << "A(const char*)" << endl; }
	A(A&) { cout << "A(A&)" << endl; }	
	
};

void func(A&) { cout << "call func(A&)" << endl; }

void func(const A&) { cout << "call func(const A&)" << endl;}

int main() {
	A a("abcdef"); // 調用A(const char*) 
	func(a); //調用func函數1 
	cout << endl;
    func("asdfasdf"); //調用func函數2 
}

運行結果如下
在這裏插入圖片描述
理解:
第一行輸出A(const char*) 爲A a(“abcdef”) 調用構造函數;
第二行輸出call func(A&) 表示調用func過程沒有任何拷貝過程;
第四行輸出 A(const char*) 是關鍵點,代表這個字符串對象先調用A(const char*) 構造函數然後在把生成的對象作爲const引用傳遞給參數。函數參數必須是const才能被接受,如果你在func函數裏面需要進行非const的操作,則首先需要一個進行一個 const_cast<A&> 轉型 (我只知道必須加const,不知道爲什麼要加const,有這方面詳細的文檔的哥們請留言)
簡而言之:函數參數是const的引用具有調用構造函數複製新對象的能力(但不是一定會複製新對象)

對繼承的影響

#include <iostream>

class Base {
public:
	//const Base&如果改爲 Base& 編譯將不通過 
    friend std::ostream&operator << (std::ostream& ,const Base&) { }
};

class A:public Base { };

int main() {
	std::cout << A(); // 調用Base的operator << 方法,需要對A對象轉型,只能轉爲const Base& 
}

簡而言之:加了const可以轉爲基類引用,而不需要複製新的對象

一個複雜的例子

這是我編寫的一份關於繼承和重載<< 的代碼,代碼雖然短,內容相當多,需要好好理解。

#include <iostream>
#include <string>

using namespace std;
 
class Base {
    string data;
public:
	virtual void setdata(string& data) { this->data = data; }
    virtual void setdata(const string& data){ this->data = data; }
    friend ostream&operator << (ostream& os,const Base& b) { // 如果把const刪除則導致輸出A對象失敗,可以刪除試下 
        os << b.data;
        return os;
    }
};

class A:public Base {
public:
    virtual void func() { }
    A() { }
    A(string& data) { setdata(data); }
    A(const char* data) { setdata(data); }
    A(const string& data) { setdata(const_cast<string&>(data)); } // 使用了const_cast 對const對象轉型 
};

void func(const A& s) {
	cout << s << endl; // 匹配到 ostream&operator << (ostream& os,const Base& b); 函數 ;
}

int main() {
	cout << A("1234") << endl; //A("1234")調用了構造函數A(const string& data); 使用了上面的技巧
	func("5678"); // "5678"先調用A(const char*data) 構造,然後setdata(data)在調用 void setdata(const string& data) 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章