???
圖源:文心一言
聽課筆記簡單整理,供小伙伴們參考,包含以下內容“🐋3.11 引用類型、🐋3.14 內聯函數、🐋3.15 默認參數值、🐋3.16 函數重載、🐋3.17 C++系統函數”~🥝🥝
- 第1版:聽課的記錄代碼~🧩🧩
編輯:梅頭腦🌸
審核:文心一言
目錄
🐳課程來源
🐳函數
🐋3.11 引用類型
🐋3.14 內聯函數
🐋3.15 默認參數值
🐋3.16 函數重載
🐋3.17 C++系統函數
🔚結語
🐳課程來源
- 鄭莉老師的公開課:🌸C++語言程序設計基礎 - 清華大學 - 學堂在線 (xuetangx.com)
🐳函數
🐋3.11 引用類型
🧩題目
輸入兩個整數交換后輸出(值傳遞)
📇算法思路
因為返回值只能返回1個值,而不能返回2個數字交換過的值,所以這個題目使用引用。
??算法代碼
#include <iostream>
using namespace std;void swap(int& a, int& b) {int t = a;a = b;b = t;
}int main()
{int x = 5, y = 10;cout << "x = " << x << ", y = " << y << endl;swap(x, y);cout << "x = " << x << ", y = " << y << endl;return 0;
}
📇執行結果
?
📇代碼解釋
當進行值交換時,注意函數聲明?
void swap(int& a, int& b)
。如果修改為?void swap(int a, int b)
,則無法完成值的交換功能。原因是,在后一種情況下,a
?和?b
?是通過值傳遞的,即傳遞的是?x
?和?y
?的副本。雖然在?swap
?函數內部更改了?a
?和?b
?的值,但這些更改不會影響到原始的?x
?和?y
。而通過在參數前加上引用符號?
&
,我們實際上傳遞的是?x
?和?y
?的地址。這樣,在函數內部對?a
?和?b
?所做的任何修改都會直接反映在原始的?x
?和?y
?上,從而實現了值的交換。
引用在C++中是一個很有用的特性,它提供了對變量的直接別名訪問,而不是通過指針的間接訪問。雖然引用在某些情況下可能引發安全問題(比如懸掛引用,即引用了一個已經被銷毀的對象的引用),但這并不意味著引用本身不安全或應該避免使用。相反,當正確使用時,引用可以提高代碼的可讀性和效率。
以下是一些推薦使用引用的場景:
函數參數:當你想在函數內部修改傳遞進來的變量時,引用是一個很好的選擇。通過傳遞引用而不是值,你可以避免復制的開銷,并且函數可以直接修改原始數據。
返回值:雖然通常建議通過值返回小型對象,但對于大型對象或容器(如
std::vector
、std::string
等),通過引用返回可能更有效。然而,需要注意的是,你不能返回局部變量的引用,因為局部變量在函數返回后會被銷毀,導致懸掛引用。在這種情況下,你應該返回一個新對象或傳遞一個輸出參數。避免復制開銷:當處理大型對象或數據結構時,通過引用傳遞它們可以避免復制整個對象的開銷。
多態性:在面向對象編程中,引用經常與基類和派生類一起使用,以實現多態行為。通過基類引用調用虛函數時,會調用相應對象類型的實現。
范圍基于的for循環:C++11引入了范圍基于的for循環,它使用引用來遍歷容器中的元素,避免了不必要的復制。
性能優化:在某些性能關鍵的場景中,使用引用可以避免不必要的內存分配和釋放,從而提高程序的性能。
然而,需要注意的是,過度使用引用也可能導致代碼難以理解和維護。因此,在使用引用時應該權衡其優點和潛在的復雜性。
🐋3.14 內聯函數
🧩題目
計算圓的面積。
📇算法思路
本例僅涉及到乘法,為了提高計算效率,使用內聯函數。
??算法代碼
#include <iostream>
using namespace std;const double PI = 3.14159265358979;
inline double calArea(double radius) {return PI * radius * radius;
}int main()
{double r = 3.0;double area = calArea(r);cout << area << endl;return 0;
}
📇執行結果
?
📇代碼解釋
本行代碼?
inline double calArea(double radius)
?中的?inline
?關鍵字表明?calArea
?函數是一個內聯函數。內聯函數(Inline Function)是C++中的一種函數優化技術。通過在函數聲明前添加
inline
關鍵字,開發者可以建議編譯器將函數的調用替換為函數體本身的代碼,這種替換通常發生在編譯時期。內聯函數的目的是減少函數調用的開銷,提高程序的執行效率。內聯函數的特點:
- 內聯替換:內聯函數的代碼通常會被直接插入到調用點(可以簡單理解為函數直接粘在main函數中執行),從而消除函數調用的開銷,如參數壓棧、跳轉到函數體、執行函數后返回等。
- 編譯時期決定:是否真正內聯一個函數是由編譯器在編譯時期決定的。
inline
關鍵字只是對編譯器的建議,編譯器可以選擇忽略它(具體來說,比較機智的編譯器可以自己識別哪些適合作為內聯函數編譯,哪些不適合)。- 定義在頭文件中:由于內聯函數的代碼需要在每個調用點都可用,因此內聯函數通常定義在頭文件中,以便在包含該頭文件的每個源文件中都可見。
- 適用于小型函數:內聯最適合那些體積小、執行速度快且調用頻繁的函數。對于大型函數,內聯可能會導致代碼膨脹,反而降低性能。
- 無函數調用開銷,但有代碼膨脹風險:內聯可以避免函數調用的開銷,但如果一個函數被內聯多次,它的代碼就會在最終的可執行文件中出現多次,導致代碼膨脹。
使用內聯函數的注意事項:
- 內聯函數應該簡潔且執行快速,避免包含循環和遞歸調用。
- 避免在頭文件中定義大型的內聯函數,這會導致包含該頭文件的每個源文件都包含該函數的完整代碼,增加編譯時間和最終可執行文件的大小。
- 謹慎使用內聯,特別是在性能敏感的代碼中。通過性能測試和剖析來確定是否真的需要內聯某個函數。
🐋3.15 默認參數值
🧩題目
計算長方體的體積。
📇算法思路
emm...長方體的體積 = 長 x 寬 x 高 這樣子...
??算法代碼
#include <iostream>
#include <iomanip>
using namespace std;int getVolume(int length, int width = 3, int height = 3);int main()
{const int X = 10, Y = 12, Z = 15;cout << "Some box data is ";cout << getVolume(X, Y, Z) << endl;cout << "Some box data is ";cout << getVolume(X, Y) << endl;cout << "Some box data is ";cout << getVolume(X) << endl;return 0;
}int getVolume(int length, int width, int height) {cout << setw(5) << length << setw(5) << width << setw(5) << height << '\t';return length * width * height;
}
📇執行結果
?
📇代碼解釋
- int getVolume(int length, int width = 3, int height = 3); 這段代碼,表示 width 與 height均有默認初始值,但用戶也可以自行輸入 width 與 height 的參數覆蓋這2個默認值,例如:
- cout << getVolume(X, Y, Z) << endl; 這段代碼,傳入?length = X = 10,width = Y = 12,height = Z = 15;
- cout << getVolume(X, Y) << endl; 這段代碼,傳入?length = X = 10,width = Y = 12,height = 3(默認值);
- cout << getVolume(X) << endl; 這段代碼,傳入?length = X = 10,width = 3(默認值),height = 3(默認值);
注意:
默認參數的順序:默認參數必須從右到左連續。也就是說,如果一個參數有默認值,那么它右邊的所有參數也都必須有默認值。例如:
int func(int a, int b = 10, int c = 20); // 合法 int func(int a = 10, int b, int c = 20); // 錯誤!'b' 沒有默認值,但 'a' 有。
- 默認參數與函數重載:默認參數可以被視為函數重載的一種簡化形式。但是,當同時使用默認參數和函數重載時,需要注意可能產生的歧義。編譯器會優先選擇參數最匹配的函數,而不是選擇有更多默認參數的函數。
- 默認參數的值:默認參數的值可以是常量、全局變量,甚至可以是函數。但是,默認參數的值在函數聲明時確定,而不是在函數調用時確定。因此,如果默認參數是一個變量,那么該變量的值將是函數聲明時的值,而不是函數調用時的值。
- 默認參數在頭文件中定義:通常,函數的聲明放在頭文件中,而函數的定義放在源文件中。當使用默認參數時,應將默認參數放在函數聲明中(即在頭文件中),而不是在函數定義中。這樣可以確保所有包含該頭文件的源文件都能看到相同的默認參數。
🐋3.16 函數重載
🧩題目
求 整數、浮點數的平方和。?
📇算法思路
功能相同,但僅參數類型與返回類型不同的兩個函數,可以使用函數重載(使用同一個名稱),以方便程序員的調用。
??算法代碼
#include <iostream>
using namespace std;int sumOfSquare(int a, int b) {return a * a + b * b;
}
double sumOfSquare(double a, double b) {return a * a + b * b;
}int main()
{int m, n;cout << "Enter two integer:";cin >> m >> n;cout << "Their sum of square:" << sumOfSquare(m, n) << endl;double x, y;cout << "Enter two real number:";cin >> x >> y;cout << "Their sum of square:" << sumOfSquare(x, y) << endl;return 0;
}
📇執行結果
輸入整數:3 5,浮點數:3.5 5.5的執行結果:
📇代碼解釋
int sumOfSquare(int a, int b) 與 double sumOfSquare(double a, double b) ,函數名相同,但是參數類型與返回類型不同,屬于函數重載。
函數重載是指在同一作用域內,可以有一組具有相同名字但參數數量或類型不同的函數。編譯器會根據調用時提供的參數數量和類型來選擇最合適的函數進行調用。
函數重載的注意事項:
參數差異:重載的函數必須通過參數的數量、類型或順序來區分。僅僅返回類型的不同并不足以構成重載。
最佳匹配:當調用重載函數時,編譯器會嘗試找到與提供的參數最匹配的函數。如果沒有找到確切匹配,編譯器可能會嘗試通過隱式類型轉換來找到匹配,這可能會導致不期望的行為。
避免歧義:設計重載函數時,要確保不會出現歧義性調用。例如,如果兩個重載函數都可以通過隱式類型轉換來匹配同一組參數,編譯器將無法決定應該調用哪一個,從而導致編譯錯誤。對于重載函數,每個重載都應該有清晰的文檔和注釋,說明它的用途、參數和返回值。這有助于其他開發者理解和使用這些函數。
謹慎使用默認參數:默認參數和函數重載在某些情況下可以互換使用,但它們有不同的優缺點。使用默認參數可以減少需要編寫的函數數量,但可能會使函數簽名變得復雜。而函數重載可以提供更清晰的語義,但可能會導致更多的代碼重復。在選擇時,應根據具體情況權衡利弊。
🐋3.17 C++系統函數
🧩題目
求 特定角度的三角函數計算值。?
📇算法思路
調用庫函數 cmath 中的 sin、cos、tan~
??算法代碼
#include <iostream>
#include <cmath>
using namespace std;
const double PI = 3.14159265358979;int main()
{double angle;cout << "Please enter an angle:";cin >> angle;double radian = angle * PI / 180;cout << "sin(" << angle << ") = " << sin(radian) << endl;cout << "cos(" << angle << ") = " << cos(radian) << endl;cout << "tan(" << angle << ") = " << tan(radian) << endl;return 0;
}
📇執行結果
輸入整數:30 的執行結果:
📇知識擴展
C++常用庫
C++ 標準庫提供了大量的函數和類,用于處理各種常見的編程任務。以下是一些 C++ 中常用的庫函數和它們所屬的庫:
輸入/輸出流庫 (iostream)
std::cin
: 用于從標準輸入讀取數據。std::cout
: 用于向標準輸出寫入數據。std::cerr
: 用于向標準錯誤輸出寫入數據。std::clog
: 用于向標準日志輸出寫入數據。字符串庫 (string)
std::string
: 表示字符串的類。std::getline()
: 從輸入流中讀取一行文本。std::stoi()
,?std::stol()
,?std::stoll()
: 將字符串轉換為整數。std::stof()
,?std::stod()
,?std::stold()
: 將字符串轉換為浮點數。容器庫 (vector, map, set, etc.)
std::vector
: 可動態調整大小的數組。std::map
: 關聯數組,存儲鍵值對。std::set
: 存儲唯一元素的集合。std::unordered_map
,?std::unordered_set
: 無序的 map 和 set。算法庫 (algorithm)
std::sort()
: 對容器中的元素進行排序。std::find()
: 在容器中查找元素。std::binary_search()
: 對已排序的容器進行二分查找。std::transform()
: 對容器中的元素進行轉換。數值庫 (numeric)
std::accumulate()
: 計算容器中元素的累積和或其他二元操作的累積結果。std::inner_product()
: 計算兩個容器的內積。std::iota()
: 為容器中的元素填充連續的遞增值。文件流庫 (fstream)
std::ifstream
: 用于從文件讀取數據的輸入文件流。std::ofstream
: 用于向文件寫入數據的輸出文件流。std::fstream
: 可用于讀寫文件的文件流。時間庫 (chrono)
std::chrono::system_clock
: 獲取系統時間。std::chrono::steady_clock
: 獲取穩定的時間間隔,不受系統時間調整影響。std::chrono::duration_cast()
: 轉換時間間隔的精度。線程庫 (thread)
std::thread
: 表示線程的類。std::this_thread::sleep_for()
: 使當前線程休眠指定的時間間隔。std::mutex
: 互斥鎖,用于同步線程。異常處理庫 (exception)
std::exception
: 所有標準異常的基類。std::throw_with_nested()
: 拋出嵌套異常。std::rethrow_if_nested()
: 重新拋出嵌套異常(如果有)。其他常用庫
std::random
: 用于生成隨機數。std::regex
: 用于正則表達式匹配和操作。std::atomic
: 用于多線程編程中的原子操作。std::optional
: 表示可能包含值或為空的包裝器。這只是 C++ 標準庫中的一小部分。實際上,C++ 標準庫非常龐大,提供了各種各樣的功能來支持各種編程需求。在使用這些庫時,建議查閱相關的文檔和參考資料以獲取更詳細的信息和示例代碼。
🔚結語
博文到此結束,寫得模糊或者有誤之處,期待小伙伴留言討論與批評,督促博主優化內容{例如有錯誤、難理解、不簡潔、缺功能}等,博主會頂鍋前來修改~~😶?🌫?😶?🌫?
我是梅頭腦,本片博文若有幫助,歡迎小伙伴動動可愛的小手默默給個贊支持一下,感謝點贊小伙伴對于博主的支持~~🌟🌟
同系列的博文:🌸數據結構_梅頭腦_的博客-CSDN博客
同博主的博文:🌸隨筆03 筆記整理-CSDN博客