【C++】新手入門指南(下)

文章目錄

前言

一、引用

1.引用的概念和定義

2.引用的特性

3.引用的使用

4.const引用

5.指針和引用的關系

二、內聯函數

三、nullptr

總結


前言

這篇續上篇的內容新手入門指南(上),繼續帶大家學習新知識。如果你感興趣歡迎訂購本專欄。


一、引用

1.引用的概念和定義

引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空間,它和它引用的變量共用同一塊內存空間。如:在水滸傳里,林沖,外號豹子頭,宋江叫"鐵牛",他們都有外號,而外號的作用跟引用一樣,相當于給一個變量取別名。

類型& 引用別名 = 引用對象;

using namespace std;
int main()
{int a = 3;int& b = a;//這里&符號表示引用取別名int& c = a;int& d = b;cout << &a << endl;//012FF88C //這里&符號表示取地址cout << &b << endl;//012FF88Ccout << &c << endl;//012FF88Ccout << &d << endl;//012FF88C//每個變量地址是一樣的return 0;
}

注:C++中為了避免引入太多的運算符,會復用C語言的一些符號,這里引用也和取地址使用了同一個符號&,大家注意區分使用。

2.引用的特性

1.引用在定義時必須初始化
引用需要初始值設定值,不然在編譯時不知道引用指向哪個變量導致報錯
using namespace std;
int main()
{
//錯誤寫法:int a=10;int& b;
//正確寫法:int a = 10;int& b = a;return 0;
}

2.一個變量可以有多個引用

一個變量可以被多個引用指向,每個引用表示這個變量的不同別名

using namespace std;
int main()
{int a = 3;int& b = a;int& c = a;int& d = b;return 0;
}

3.引用一旦引用一個實體,再不能引用其他實體

一旦引用初始化為某個變量后,就不能指向其他變量

using namespace std;
int main()
{int x = 4, y = 5;int& z = x;z=y;//這里是把變量y賦值給引用z指向的變量x,不是把引用c又指向變量yreturn 0;
}

3.引用的使用

引用主要有兩種用法是 引用傳參 引用做返回值 ;優點: 減少拷貝提高效率和改變引用對象時同時改變被引用對象

引用做參數的時候,可以避免傳值時的拷貝開銷,提高效率。

//引用傳參
using namespace std;void Swap(int& rx, int& ry)
{                           int tmp = rx;rx = ry;ry = tmp;
}
int main()
{int x = 0, y = 1;cout << x << " " << y << endl;Swap(x, y);cout << x << " " << y << endl;return 0;
}

引用做返回值的時候,在取棧頂時可以直接用引用做返回值,這樣出函數作用域對象還可以用。提高效率和可以修改返回對象

using namespace std;
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST& rs, int n = 4)
{rs.a = (STDataType*)malloc(n * sizeof(STDataType));rs.top = 0;rs.capacity = n;
}// 棧頂
void STPush(ST& rs, STDataType x)
{//assert(rs);// 滿了, 擴容if (rs.top == rs.capacity){printf("擴容\n");int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}rs.a = tmp;rs.capacity = newcapacity;}rs.a[rs.top] = x;rs.top++;
}//取棧頂
//引用做返回值
int& STTop(ST& rs)
{return rs.a[rs.top - 1];
}

4.const引用

在使用引用會出現這種情況,int& rb = a*3; double d = 12.34; int& rd = d;

a*3 和12.34 保存在?個臨時對象中, int& rd = d 發生類型轉換?,在類型轉換中會產?臨時對象存儲中間值,rb和rd引用的都是臨時對象。C++規定臨時對象具有常性,不能修改。因此這里權限被放大,需用常引用才可以。 所以如果引用對象是需要放在臨時變量就有常性的,就需要使用常引用,權限可以縮小、平移但不能放大。
using namespace std;
int main()
{//權限不能放大:const可以把變量變常量,不能常量變變量const int a = 10;//int& ra = a;//權限可以平移://const int& ra = a;//權限可以縮小://因為const起常量的作用,所以rb雖然和b是同一個地址,但是rb不能改大只能往比b小的改int b = 20;const int& rb = b;//對于指針也是一樣//權限不能放大const int* pa = &a;//int* ppa = pa;//權限可以縮小int* pb = &b;const int* ppb = pb;return 0;
}

5.指針和引用的關系

  1. 引用是一個變量的取別名不開空間,指針是存儲一個變量地址,要開空間
  2. 引用在定義時必須初始化,指針建議初始化,但不是必須的。
  3. 引用在初始化時引用一個對象后,就不能再引用其他對象;而指針可以在任何時候可以改變指向對象。
  4. 引用可以直接訪問指向對象,指針需要解引用才是訪問指向對象。
  5. sizeof中含義不同,引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32位平臺下占4個字節,64位下是8個字節)
  6. 引用不存在空引用,比指針更安全,指針很容易出現空指針和野指針的問題。

二、內聯函數

在C語言中,我們了解宏的定義和用法,在實現宏時會發現宏有很多弊端,比如在宏寫一個加法函數 #define ADD(a, b) ((a) + (b))? 時,因為宏容易出錯在語法上會出“為什么里層要加括號” 、“為什么外層要加括號”以及“為什么不能加分號”等問題。 因此C語言實現宏函數也會在預處理時替換展開,但是宏函數實現很復雜很容易出錯的,且不方便調試;所以設計 inline內聯函數 來代替C的宏函數。
用inline修飾的函數叫做內聯函數。 編譯時C++編譯器會在調用的地方展開內聯函數,這樣調用內聯 函數就需要建立棧幀了,就可以提高效率。
注:vs編譯器 debug版本下面默認是不展開inline的,這樣方便調試,debug版本想展開需要設置一下以下兩個地方。

從匯編層上看內聯函數是否展開,在VS編譯器上是默認不展開的,但設置一下是會展開的。

#include<iostream>
using namespace std;
inline int Add(int x, int y)
{int ret = x + y;ret += 1;ret += 1;return ret;
}
int main()
{// 可以通過匯編觀察程序是否展開// 有call Add語句就是沒有展開,沒有就是展開了int ret = Add(1, 2);cout << Add(1, 2) * 5 << endl;return 0;
}

沒設置之前不展開:

設置之后展開:

inline對于編譯器而言只是一個建議,也就是說,你加了inline編譯器也可以選擇在調用的地方不展開,不同編譯器關于inline什么情況展開各不相同,因為C++標準沒有規定這個。 inline適用于頻繁調用的短小函數 ,對于遞歸函數,代碼相對多一些的函數,加上inline也會被編譯器忽略。
inline不建議聲明和定義分離到兩個文件,分離會導致鏈接錯誤。因為inline被展開,就沒有函數地址,鏈接時會出現報錯。?
因為分離在兩個文件,會導致預處理替換;編譯時會出現語法錯誤;調用時,聲明和定義在兩個文件中,在找聲明時,通過鏈接找到符號表,這時找不到定義,就會出現鏈接錯誤
例子如下:
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{f(10);return 0;
}

會發生鏈接錯誤,編譯報錯:無法解析的外部符號 "void __cdecl f(int)" (?f@@YAXH@Z)

因為函數的聲明和定義分離,在鏈接時出錯從而編譯報錯。

三、nullptr

在C語言中,NULL本質是一個宏。

C++中NULL可能被定義為字面常量0,或者C中被定義為無類型指針(void*)的常量。
不論采取何種定義,在使用空值的指針時,都不可避免的會遇到一些麻煩,本想通過f(NULL)調用指針版本的 f(int*)函數,但是由于NULL被定義成0,調用了f(int x),因此與程序的初衷相悖。f((void*)NULL); 調用會報錯。
#include<iostream>
using namespace std;
void f(int x)
{cout << "f(int x)" << endl;
}
void f(int* ptr)
{cout << "f(int* ptr)" << endl;
}
int main()
{f(0);// 本想通過f(NULL)調?指針版本的f(int*)函數,但是由于NULL被定義成0,調?了f(int
x),因此與程序的初衷相悖。f(NULL);f((int*)NULL);// 編譯報錯:error C2665: “f”: 2 個重載中沒有?個可以轉換所有參數類型// f((void*)NULL);f(nullptr);return 0;
}

運行結果:

因此,C++11中引入nullptr,nullptr是一個特殊的關鍵字,nullptr是一種特殊類型的字面量,它可以轉換成任意其他類型的指針類型。使用nullptr定義空指針可以避免類型轉換的問題,因為nullptr只能被隱式地轉換為指針類型,而不能被轉換為整數類型。


總結

非常感謝大家閱讀完這篇博客。希望這篇文章能夠為您帶來一些有價值的信息和啟示。如果您發現有問題或者有建議,歡迎在評論區留言,我們一起交流學習。

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

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

相關文章

uniapp-商城-33-shop 布局搜索頁面以及u-search

shop頁面上有一個搜索&#xff0c;可以進行商品搜索&#xff0c;這里我們先做一個頁面布局&#xff0c;后面再來進行數據i聯動。 1、shop頁面的搜索 2、搜索的頁面代碼 <navigator class"searchView" url"/pagesub/pageshop/search/search"> …

SAP 采購訂單如何防止開票數量 大于 收貨數量呢

配置點如下&#xff1a; 事務碼&#xff1a;OMRM&#xff0c;配置如下 當過賬開票的數量 大于收貨數量的時候會提示如下&#xff1a;

Kotlin 的 suspend 關鍵字

更多相關知識 Kotlin 的 suspend 關鍵字是 Kotlin 協程的核心組成部分&#xff0c;它用于標記一個函數可以被掛起&#xff08;暫停執行&#xff09;并在稍后恢復執行&#xff0c;而不會阻塞線程。 理解 suspend 的作用需要從以下幾個方面入手&#xff1a; 1. 允許非阻塞的異步…

UDS診斷協議iso-14229 15765

Diagnostic request 形式多種: 1.SID+DID 2.SID+Sub-Func+DID 3.SID+Sub-Func SID占1個Byte,Sub-func占一個Byte,DID通常兩個Byte eg.10 01 (SID+Sub-Func) 10 03 05 02 (SID+Sub-Func+DID) 22 02 00 (SID+DID) 肯定響應抑制位 抑制正響應信息除非是收到NRC 0x78的情況下 不…

記錄一次使用面向對象的C語言封裝步進電機驅動

簡介 (2025/4/21) 本庫對目前僅針對TB6600驅動下的42步進電機的基礎功能進行了一定的封裝, 也是我初次嘗試以面向對象的思想去編寫嵌入式代碼, 和直流電機的驅動步驟相似在調用stepmotor_attach()函數和stepmotor_init()函數之后僅通過結構體數組stepm然后指定枚舉變量中的id即…

[創業之路-376]:企業法務 - 創業,不同的企業形態,個人承擔的風險、收益、稅費、成本不同

在企業法務領域&#xff0c;創業時選擇不同的企業形態&#xff0c;個人在風險承擔、收益分配、稅費負擔及運營成本方面存在顯著差異。以下從個人獨資企業、合伙企業、有限責任公司、股份有限公司四種常見形態展開分析&#xff1a; 一、個人承擔的風險 個人獨資企業 風險類型&…

GNOME桌面隱藏回收站和分區

dconf-editor 搜索 trash&#xff0c;關閉 show-trash 搜索 volumes&#xff0c;關閉 show-volumns

準確--Tomcat更換證書

具體意思是&#xff1a; Starting Coyote HTTP/1.1 on http-8080: HTTP 連接器&#xff08;端口 8080&#xff09;啟動成功了。嚴重: Failed to load keystore type PKCS12 with path conf/jlksearch.fzsmk.cn.pfx due to failed to decrypt safe contents entry: javax.crypt…

禁止ubuntu自動更新

由于ubuntu server和desktop版本都默認 啟動了&#xff0c;自動更新內核的操作。這對于生 產環境來說是不友好的。容易導致億賽通 無法啟動 默認開啟了內核自動更新所以我們關閉自 動內核更新。 1.禁止更新執行 sudo apt-mark hold linux-image-generic linux-headers-generic…

vue3 + element-plus中el-drawer抽屜滾動條回到頂部

el-drawer抽屜滾動條回到頂部 <script setup lang"ts" name"PerformanceLogQuery"> import { ref, nextTick } from "vue"; ...... // 詳情 import { performanceLogQueryByIdService } from "/api/performanceLog"; const onD…

【重走C++學習之路】16、AVL樹

目錄 一、概念 二、AVL樹的模擬實現 2.1 AVL樹節點定義 2.2 AVL樹的基本結構 2.3 AVL樹的插入 1. 插入步驟 2. 調節平衡因子 3. 旋轉處理 4. 開始插入 2.4 AVL樹的查找 2.5 AVL樹的刪除 1. 刪除步驟 2. 調節平衡因子 3. 旋轉處理 4. 開始刪除 結語 一、概念 …

char32_t、char16_t、wchar_t 用于 c++ 語言里存儲 unicode 編碼的字符,給出它們的具體定義

&#xff08;1&#xff09; #include <iostream> #include <string>int main() { std::u16string s u"C11 引入 char16_t"; // 定義 UTF-16 字符串for (char16_t c : s) // 遍歷輸出每個 char16_t 的值std::cout << std::hex << (…

redis數據類型-基數統計HyperLogLog

redis數據類型-基數統計HyperLogLog 文檔 redis單機安裝redis常用的五種數據類型redis數據類型-位圖bitmap 說明 官網操作命令指南頁面&#xff1a;https://redis.io/docs/latest/commands/?nameget&groupstringHyperLogLog介紹頁面&#xff1a;https://redis.io/docs…

邏輯思維:從混沌到秩序的理性推演在軟件開發中的應用

引言 在軟件開發的過程中&#xff0c;邏輯思維就像是開發者的“GPS導航”&#xff0c;幫助我們從混沌的需求中找到清晰的解決方案。想象一下&#xff0c;如果沒有邏輯思維&#xff0c;我們可能會在需求的海洋中迷失方向&#xff0c;最終寫出一堆“看似聰明但毫無意義”的代碼。…

Spring AI Alibaba Graph基于 ReAct Agent 的天氣預報查詢系統

1、在本示例中&#xff0c;我們僅為 Agent 綁定了一個天氣查詢服務&#xff0c;接收到用戶的天氣查詢服務后&#xff0c;流程會在 AgentNode 和 ToolNode 之間循環執行&#xff0c;直到完成用戶指令。示例中判斷指令完成的條件&#xff08;即 ReAct 結束條件&#xff09;也很簡…

HCIP(綜合實驗2)

1.實驗拓補圖 2.實驗要求 1.根據提供材料劃分VLAN以及IP地址&#xff0c;PC1/PC2屬于生產一部員工劃分VLAN10,PC3屬于生產二部劃分VLAN20 2.HJ-1HJ-2交換機需要配置鏈路聚合以保證業務數據訪問的高帶寬需求 3.VLAN的放通遵循最小VLAN透傳原則 4.配置MSTP生成樹解決二層環路問題…

使用 rebase 輕松管理主干分支

前言 最近遇到一個技術團隊的 dev 環境分支錯亂&#xff0c;因為是多人合作大家各自提交信息&#xff0c;導致出現很多交叉合并記錄&#xff0c;讓對應 log 看起來非常混亂&#xff0c;難以閱讀。 舉例說明 假設我們有一個項目&#xff0c;最初develop分支有 3 個提交記錄&a…

使用openssl為localhost創建自簽名

文章目錄 自簽名生成命令安裝安裝證書瀏覽器證書管理器 自簽名 生成命令 使用openssl生成私鑰和證書。 openssl req -x509 -newkey rsa:4096 -nodes -days 365 -subj "/CNlocalhost" -addext "subjectAltNameDNS:localhost" -keyout cert.key -out cer…

AI編程助手Cline之快速介紹

Cline 是一款深度集成在 Visual Studio Code&#xff08;VSCode&#xff09; 中的開源 AI 編程助手插件&#xff0c;旨在通過結合大語言模型&#xff08;如 Claude 3.5 Sonnet、DeepSeek V3、Google Gemini 等&#xff09;和工具鏈&#xff0c;為開發者提供自動化任務執行、智能…

1.微服務拆分與通信模式

目錄 一、微服務拆分原則與策略 業務驅動拆分方法論 ? DDD&#xff08;領域驅動設計&#xff09;中的限界上下文劃分 ? 業務功能正交性評估&#xff08;高內聚、低耦合&#xff09; 技術架構拆分策略 ? 數據層拆分&#xff08;垂直分庫 vs 水平分表&#xff09; ? 服務粒…