C++基礎知識

目錄

前言:

命名空間

命名空間的定義

命名空間的使用

c++輸入與輸出

缺省參數

函數重載

引用

引用的特性

常引用

引用的使用場景

引用做參數

引用做返回值

引用與指針的區別

內聯函數

內聯函數的特性


前言:

C 語言是結構化和模塊化的語言,適合處理較小規模的程序;對于復雜的問題,規模較大 程序,需要高度的抽象和建模時, C 語言則不合適;為了解決軟件危機, 20 世紀 80 年代, 計算機界提出了 OOP(object oriented programming:面向對象)思想 ,支持面向對象的程序設計語言 應運而生;
1982 年, Bjarne Stroustrup博士 C 語言的基礎上引入并擴充了面向對象的概念,發明了一 種新的程序語言。為了表達該語言與 C 語言的淵源關系,命名為 C++ ,因此: C++是基于C語言而產生的,它既可以進行C語言的過程化程序設計,又可以進行以抽象數據類型為特點的基于對象的程序設計,還可以進行面向對象的程序設計;

命名空間

由于變量 函數 類的名稱存在于全局作用域中,會導致命名沖突;

使用命名空間的目的是對標識符的名稱進行本地化,以防止命名沖突或名字污染

# include <stdio.h>
# include <stdlib.h> //stdlib.h文件中包含庫函數rand()函數
int rand = 20;       //全局變量rand與stdlib.h文件中的庫函數rand()發生命名沖突
int main()
{printf("%d\n", rand);return 0;
}
//代碼運行結果 error C2365:"rand":重定義,以前定義是"函數"

命名沖突的場景:

1.? 程序員定義的變量與庫函數名相沖突;

2.? 多人協作同一個大型項目,程序員之間發生函數名命名沖突;

命名空間的定義

程序設計者根據需要指定一些帶有名字的空間域,將一些全局實體分別存放于各個命名空間中,從而與其他全局實體分割出來;

定義命名空間的關鍵字namespace

語法: namespce 命名空間名 { 命名空間成員 }

//命名空間名為Qspace
namespace Qspace 
{//定義變量int a = 10;//定義函數int Add(int x, int y){return x + y;}//定義類型struct ListNode{int val;struct ListNode* next;};
}

?命名空間嵌套定義

namespace Addspace
{int Add(int x, int y){return x + y;}//嵌套定義命名空間Subspacenamespace Subspace{int sub(int x, int y){return x - y;}}
}

?多個文件定義同名的命名空間,編譯器最終會合成同一個命名空間中

//test.h文件
# include <iostream>
namespace MSpace
{int Mul(int x, int y){return x*y;}
}//test.cpp文件
# include "test.h"
namespace MSpace
{int Add(int x, int y){return x + y;}namespace Subspace{int sub(int x, int y){return x - y;}}
}
int main()
{int ret = MSpace::Mul(2, 3);printf("%d\n", ret);return 0;
}

命名空間的使用

方式一:加命名空間名稱及作用域限定符(::) 即命名空間名 :: 命名空間成員名

namespace Qspace 
{int a = 10;int Add(int x, int y){return x + y;}struct ListNode{int val;struct ListNode* next;};
}
int main()
{printf("%d\n", Qspace::a);  //變量的訪問方式int ret = Qspace::Add(2, 3);//函數的訪問方式printf("%d\n", ret);struct Qspace::ListNode node = { 0, NULL };//結構體類型的訪問方式return 0;
}

方式二:使用using將命名空間中某個成員引入 即using 命名空間名 :: 命名空間成員名

namespace MSpace
{int a = 10;int b = 20;
}
//using 命名空間名::命名空間成員名
using MSpace::a;int main()
{printf("%d ", a);return 0;
}

方式三 :使用using namespace 命名空間名引入即using namespace 命名空間名

using namespace 命名空間名 將整個命名空間展開,使得特定命名空間所有成員名可見,此時使用命名空間下的變量、函數不需要加作用域限定符,使得隔離失效;

namespace Addspace
{int a = 10;int Add(int x, int y){return x + y;}
}
using namespace Addspace;
int main()
{scanf("%d", &a);int ret= Add(2, 3);printf("%d\n", ret);return 0;
}

c++輸入與輸出

  • std是C++標準庫的命名空間cout為iostream所定義的標準輸出對象(控制臺)(終端)cin為iostream所定義的標準輸入對象(鍵盤),因此使用cout , cin必須包含< iostream >頭文件及按命名空間使用方法使用std;
  • endl(endline)表示換行輸出,相當于換行符,包含在<iostream>頭文件中;
  • << 流插入運算符(與cout配合使用,可以將輸出的變量或者字符串流入到cout中,cout負責輸出到終端); ?
  • >> 流提取運算符(與cin配合使用,將用戶輸入的值流入到某變量中);
  • cin以遇到空格鍵,tab鍵或者換行符作為分隔符,停止讀取;
# include <iostream>
using namespace std;
int main()
{cout << "hello world!" << endl;return 0;
}

運行結果:

//cin遇到空格鍵 Tab鍵 Enter鍵停止讀取
# include <iostream>
using namespace std;
int main()
{char a[10] = { 0 };cin >> a;cout << a << endl;return 0;
}

運行結果:

注:cout與cin可以自動識別變量類型

缺省參數

缺省參數是聲明或定義函數時為函數的形式參數指定一個默認值(缺省值)

調用該函數時,如果沒有指定實參則采用形參的缺省值,否則使用指定的實參;

# include <iostream>
using namespace std;
void Fun(int a = 10)
{cout << a << endl;
}
int main()
{Fun();   //沒有傳參時,使用形式參數的默認值Fun(20); //傳參時,使用指定的實參return 0;
}

?運行結果:

缺省參數的分類

全缺省參數:函數定義或聲明時,為該函數所有形式參數指定缺省值;

半缺省參數:函數定義或聲明時,為該函數的部分形式參數指定缺省值,但是缺省值只能從右向左給值,必須連續給值;

# include <iostream>
using namespace std;
void Fun(int a = 10,int b=20,int c=30)//全缺省參數
{cout << "a="<< a ;cout << "b="<< b ;cout << "c="<< c << endl;
}
int main()
{Fun();Fun(1);Fun(1, 2);Fun(1, 2, 3);return 0;
}

?運行結果:

# include <iostream>
using namespace std;
void Fun(int a,int b=20,int c=30)//半缺省參數
{cout << "a="<< a ;cout << "b="<< b ;cout << "c="<< c << endl;
}

注:缺省參數不能在函數聲明和定義同時出現,若聲明與定義皆具有缺省參數,恰巧兩個位置提供的值不同,此時編譯器無法確定到底該采用那個缺省值,當聲明與定義分離時,只能在函數聲明處給出缺省參數

函數重載

函數重載:C++允許在同一作用域中聲明幾個功能類似的同名函數,但是要求同名函數的
形參列表(參數個數 參數類型 類型順序)不同,返回值無要求;

//參數類型不同
int Add(int a, int b)
{return a+b;
}
double Add(double a, double b)
{return a+b;
}
//參數個數不同
int Fun(int a);
int Fun(int a,int b);
//形參類型的順序不同
int Sub(int a, char b);
int Sub(char b, int a);

為什么C++支持函數重載,而C語言不支持函數重載呢?

程序運行時,需要經歷如下階段:預處理 編譯 匯編 鏈接,而在鏈接階段會生成符號表,建立函數名與地址一一映射的關系,C語言鏈接函數地址時,采用函數名尋找函數定義,而對于同名函數無法區分函數地址,但是C++是通過函數修飾規則(如Linux下g++ 修飾規則:

_Z + 函數名字符個數+函數名+參數首字母)來區分,修飾后名字不同,自然支持了重載;

引用

引用不是新定義一個變量,而是 給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空間,它和它引用的變量 共用同一塊內存空間
語法:?? 類型&? 引用變量名(對象名) = 引用實體
//原變量與引用變量共用同一塊內存空間
int main()
{int a = 10;int& pa = a;printf("%p\n", &a);printf("%p\n", &pa);return 0;
}

運行結果:

注:引用類型與引用實體必須是相同類型;

引用的特性

引用在定義時必須初始化;

int main()
{//正確示例int a = 10;int& pa = a;//錯誤示例int b = 20;int& pc;//編譯時出錯return 0;
}

一個變量既可以有多個引用又可以給引用變量繼續取引用;

int main()
{int a = 10;int& pa = a;int& pb = a;int& pc = pa;cout << "a=" << a << endl;cout << "pa=" << pa << endl;cout << "pb=" << pb << endl;cout << "pc=" << pc << endl;return 0;
}

運行結果:

引用一旦引用一個實體,不能引用其他實體;

 int main()
{int a = 10;int& pa = a;int d = 1;// pa變成d的別名?還是d賦值給pa?pa = d;//pa的引用實體為a,讓引用變量pa引用dcout << a << endl;return 0;
}

運行結果:

將d的值賦值給pa,又因為pa是a的引用,所以a的值間接變成了1;

常引用

int main()
{const int a = 10;int& b = a;//錯誤做法const int& b = a;//正確做法return 0;
}

變量a由于const修飾具有常屬性,不可被修改;而引用變量b與原變量應具有相同屬性,不能被修改,但是引用變量放大了權限,導致編譯錯誤;

int main()
{//權限可以縮小int c = 20;const int& d = c;const int& e = 10;return 0;
}

變量c的屬性為可讀寫,引用變量d的屬性為可讀,權限縮小并不會導致編譯錯誤;

int main()
{int i = 10;double j = i;//整型提升double& rj = i;//錯誤做法const double& rm = i;//正確做法return 0;
}

當發生整型提升時,系統不是直接將其賦值給另外一個變量的,而是會創建一個常量區來存放變量提升后的結果,此時變量具有了常屬性,一旦出現權限的放大,必然導致編譯錯誤;

總結:類型轉換(整型提升 截斷)產生臨時變量,臨時變量具有常屬性;

引用的使用場景

引用做參數

C語言階段函數通過傳址調用,實現通過形參修改實參,由于形參與實參數值上相同,空間上獨立,所以實參是形參的臨時拷貝;而引用變量在語法上與原變量共用同一塊內存空間,若形參采用引用變量的方式,也可達到修改實參;

//指針方式
void Swap1(int* pa, int* pb)
{int tmp = *pa;*pa = *pb;*pb = tmp;
}
//引用方式
void Swap2(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}

引用做返回值

void Func()
{int c = 0;cout << &c << endl;
}
int main()
{Func();//Func()函數第一次調用結束,銷毀第一次為func()函數所開辟的函數棧幀Func();return 0;
}

運行結果:

?由于空間可以重復利用,第一次調用Func()函數并為其開辟函數棧幀,并在函數棧幀中為變量c分配空間,當函數運行結束后,該函數所對應的棧空間由操作系統回收,但數據是否被清理是不確定的,當第二次調用Func()函數時,仍然在該地址處創建了c這個變量;

int& Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2);Add(3, 4);cout << "Add(1,2)=" << ret << endl;return 0;
}

運行結果:

?ret其實指向的是c那塊空間的地址,當c發生了變化,ret也就會隨之發生改變;

int& Add(int a, int b)
{static int c = a + b;return c;
}
int main()
{int& ret1 = Add(1, 2);cout << "Add(1,2)=" << ret1 << endl;int& ret2 = Add(3, 4);cout << "Add(3,4)=" << ret2 << endl;return 0;
}

運行結果:

當Add()函數運行結束后,由于static修飾的局部變量存放于靜態區,出函數作用域并不會被銷毀,此時可以引用返回,但是第二次調用Add()函數發生錯誤,原因為靜態成員變量只會被初始化一次

總結:引用做返回值時,返回的數據必須由static修飾或者是存放于堆區的數據或者是全局變量等不會隨著函數調用的結束而被銷毀的數據;

引用與指針的區別

1. 引用概念上定義一個變量的別名,指針存儲一個變量地址;
2. 引用在定義時必須初始化,指針沒有要求;
3. 引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何一個同類型實體;
4. 沒有NULL引用,但有NULL指針;
5. 在sizeof中含義不同:引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32位平臺下占4個字節);
6. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小;
7. 有多級指針,但是沒有多級引用;
8. 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理;
9. 引用比指針使用起來相對更安全;

內聯函數

宏是一種在程序中定義的簡單代碼替換機制,它們通常用于定義常量或執行重復性操作,與函數不同,宏是在編譯時展開的,而不是在運行時調用;

宏的聲明方式:

 #define name( parament-list ) stuff
//其中的 parament-list 是一個由逗號隔開的符號表,它們可能出現在stuff中
//宏函數
# define Add(x,y) ((x)+(y))
int main()
{int a = 10;int b = 20;int ret = Add(10, 20);cout << "ret=" << ret << endl;return 0;
}

宏的缺點:

1、容易出錯,語法細節多;

2、不能調試(預編譯階段進行了替換);

3、沒有類型安全的檢查;

由于宏的缺點從而產生內聯函數替代宏函數;

內聯函數:以關鍵字inline修飾的函數叫做內聯函數,編譯時C++編譯器會在調用內聯函數的地方展開,沒有函數調用建立棧幀的開銷,內聯函數提升程序運行的效率;

inline int Add(int x, int y)
{return x + y;
}
int main()
{int a = 10;int b = 20;int ret = Add(10, 20);cout << "ret=" << ret << endl;return 0;
}

內聯函數的特性

  • ?inline是一種以空間換時間的做法,如果編譯器將函數當成內聯函數處理,在編譯階段,會用函數體替換函數調用,缺陷:可能會使目標文件變大,優勢:少了調用開銷,提高程序運行效率;
  • inline對于編譯器而言只是一個建議,不同編譯器關于inline實現機制可能不同,一般建議:將函數規模較小(即函數不是很長,具體沒有準確的說法,取決于編譯器內部實現)、不是遞歸、且頻繁調用的函數采用inline修飾,否則編譯器會忽略inline特性;
  • inline不建議聲明和定義分離,分離會導致鏈接錯誤。因為inline被展開,就沒有函數地址了,鏈接就會找不到,由于內聯函數所生成的地址不會進入符號表,也就沒有函數名與地址一一映射的關系,所以發生鏈接性錯誤;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/215515.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/215515.shtml
英文地址,請注明出處:http://en.pswp.cn/news/215515.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VS CODE 出錯 XHR failed

重新下載過去的版本&#xff0c;可能由于最近版本更新導致 Visual Studio Code September 2023

談談MYSQL主從復制原理

目錄 概述 要點binlog日志 主從復制過程 總結 概述 MySQL 主從復制是指數據可以從一個MySQL數據庫服務器主節點復制到一個或多個從節點。 MySQL 默認采用異步復制方式。從節點不用一直訪問主服務器來更新自己的數據&#xff0c;數據的更新可以在遠程連接上進行&#xff0…

Volatility3內存取證工具安裝及入門在Linux下的安裝教程

1-1. Volatility3簡介 Volatility 是一個完全開源的工具&#xff0c;用于從內存 (RAM) 樣本中提取數字工件。支持Windows&#xff0c;Linux&#xff0c;MaC&#xff0c;Android等多類型操作系統系統的內存取證。 針對競賽這塊&#xff08;CTF、技能大賽等&#xff09;基本上都…

websocket vue操作

let websocket: WebSocket; /** websocket測試 */ function connectWebsocket() {if (typeof WebSocket "undefined") {console.log("您的瀏覽器不支持WebSocket");return;}// let ip window.location.hostname ":8080";let ip "10.192…

瑞薩RZ/G2L核心板Linux Log目錄文件詳解

為了排除系統問題&#xff0c;監控系統健康狀況以及了解系統與應用程序的交互方式&#xff0c;我們需要了解各log文件的作用&#xff0c;以G2L中yocto文件系統為例&#xff0c;在系統/var/log/目錄下會存放記錄系統中各個部分的log文件作用如下&#xff1a; 1. 文件詳情 下圖…

Ubuntu系統部署Inis博客并使用內網穿透發布到公網隨時隨地遠程訪問

目錄 前言 推薦 1. Inis博客網站搭建 1.1. Inis博客網站下載和安裝 1.2 Inis博客網站測試 1.3 cpolar的安裝和注冊 2. 本地網頁發布 2.1 Cpolar臨時數據隧道 2.2 Cpolar穩定隧道&#xff08;云端設置&#xff09; 2.3.Cpolar穩定隧道&#xff08;本地設置&#xff09;…

鴻蒙原生應用/元服務開發-Stage模型能力接口(二)

ohos.app.ability.AbilityConstant (AbilityConstant)一、說明 AbilityConstant提供Ability相關的枚舉&#xff0c;包括設置初次啟動原因、上次退出原因、遷移結果、窗口類型等。本模塊首批接口從API version 9開始支持。后續版本的新增接口&#xff0c;采用上角標單獨標記接口…

matlab 最小二乘擬合平面(拉格朗日乘子法)

目錄 一、算法原理二、代碼實現三、結果展示本文由CSDN點云俠原創,原文鏈接。博客長期更新,爬蟲自重。 一、算法原理 設擬合出的平面方程為: a x + b y &#

Linux筆記之systemctl命令詳解

Linux筆記之systemctl命令詳解 code review! 文章目錄 Linux筆記之systemctl命令詳解systemctl restart docker 詳解 systemctl 是一個用于管理 systemd 服務的命令行工具。systemd 是一個用于啟動、停止和管理 Linux 系統中的進程的系統和服務管理器。下面是一些常見的 syst…

機器視覺系統選型-條形光源分類及應用場景

標準面光源 從平坦發光面照射漫射光 機械零件尺寸測量電子元件、IC的外形檢測邊緣缺陷檢測服裝紡織、食品包裝檢測 中孔面光源 從相機的同軸方向照射漫射光 金屬零件缺陷檢測金屬外殼檢測大面積電子元件的字符識別 平行面光源 照射平行度較高的漫射光玻璃瓶直徑測量螺釘牙輪…

Android studio 離線配置gradle

Gradle Distributions Gradle Distributions 查看gradle 文件夾下 gradle-wrapper.properties文件中的distributionUrl 版本號 然后在上邊網站下載對應需要的gradle對應版本 下載后復制到 gradle wrapper文件下&#xff0c;同時修改 distributionUrl 指向本地文件 然后同步就…

xtu oj 1233 Cycle Matrix

題目描述 給定N&#xff0c;輸出一個N*N的矩陣&#xff0c;矩陣為N層&#xff0c;每層是一個字符&#xff0c;從A到Z。 比如說N3,矩陣為 CCCCC CBBBC CBABC CBBBC CCCCC輸入 第一行是一個整數K&#xff08;K≤50&#xff09;,表示樣例數。 每個樣例占1行&#xff0c;為一個整…

647.回文子串

給你一個字符串 s &#xff0c;請你統計并返回這個字符串中 回文子串 的數目。 回文字符串 是正著讀和倒過來讀一樣的字符串。 子字符串 是字符串中的由連續字符組成的一個序列。 具有不同開始位置或結束位置的子串&#xff0c;即使是由相同的字符組成&#xff0c;也會被視作…

迷你型洗衣機好用嗎?口碑好的四款小型洗衣機推薦

隨著人們的生活水平的提升&#xff0c;越來越多小伙伴來開始追求更高的生活水平&#xff0c;一些智能化的小家電就被發明出來&#xff0c;而且內衣洗衣機是其中一個。現在通過內衣褲感染到細菌真的是越來越多&#xff0c;所以我們對內衣褲的清洗頻次會高于普通衣服&#xff0c;…

輕量封裝WebGPU渲染系統示例<47>- 多種光源(源碼)

當前示例源碼github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MultiLightsShading.ts 當前示例運行效果: 此示例基于此渲染系統實現&#xff0c;當前示例TypeScript源碼如下: export class MultiLightsShading {private mRscene…

STM32 DAC+串口

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、DAC是什么&#xff1f;二、STM32 DAC1.什么型號有DAC2. 簡介3. 主要特點4. DAC框圖5. DAC 電壓范圍和引腳 三、程序步驟總結 前言 提示&#xff1a;這里可…

Runtime

Runtime 概念&#xff1a; Runtime是一套底層純C語言API&#xff0c;OC代碼最終都會被編譯器轉化為運行時代碼&#xff0c;通過消息機制決定函數調用方式&#xff0c;這也是OC作為動態語言使用的基礎。Runtime的最大特征就是實現了OC語言的動態特性。 消息機制原理 在Objec…

代碼隨想錄27期|Python|Day13|棧與隊列|239. 滑動窗口最大值 (一刷至少需要理解思路)|347.前 K 個高頻元素 (一刷至少需要理解思路)

239. 滑動窗口最大值 單調隊列 滑動窗口中的隊列一直保持出口大&#xff0c;入口小的順序。&#xff08;圖&#xff1a;代碼隨想錄&#xff09; 1、每次有新的元素進入&#xff08;也就是滑動窗口移動后&#xff09;&#xff0c;都需要先和入口的元素比較大小&#xff0c;如果…

BDD100K數據集

官網:BDD100K (vis.xyz)????? 論文&#xff1a;[1805.04687] BDD100K: A Diverse Driving Dataset for Heterogeneous Multitask Learning (arxiv.org) github:bdd100k/bdd100k: Toolkit of BDD100K Dataset for Heterogeneous Multitask Learning - CVPR 2020 Oral Pap…

特發性震顫會導致其他并發癥嗎?

特發性震顫是一種較為常見的神經系統疾病&#xff0c;其主要癥狀是姿勢性震顫&#xff0c;常常在手部開始&#xff0c;并可逐漸累及頭部、下肢等其他部位。雖然特發性震顫的主要癥狀是震顫&#xff0c;但該病也可能導致其他并發癥。下面將詳細介紹特發性震顫可能引起的并發癥。…