C++基本知識 —— 缺省參數·函數重載·引用

C++基本知識 —— 缺省參數·函數重載·引用

  • 1. 缺省參數
  • 2. 函數重載
  • 3. 引用
    • 3.1 引用的基礎知識
    • 3.2 引用的作用
    • 3.3 const 引用
    • 3.4 指針與引用的關系

1. 缺省參數

什么是缺省參數?缺省參數是聲明或定義函數時為函數的參數指定一個缺省值。在調用該函數的時候,如果沒有指定實參則采用該形參的缺省值(默認值),否則使用指定的實參。缺省參數也就做默認參數,缺省值一般都是字面量常量,也可以是全局變量;傳參時實參只能從左向右傳,且若傳參時,只傳了一個實參,那么函數的參數列中的第一個形參的值就是這個實參的值;缺省參數分為全缺省和半缺省參數。全缺省就是全部形參使用的都是缺省值。下面用具體的代碼來解釋上述概念:

// 這就是一個全缺省函數
void Func(int x = 10, int y = 20, int z = 30)
{cout << "x = " << x << "\ty = " << y << "\tz = " << z << endl;
}int main()
{//不傳參 x y z 使用的都是缺省值Func(); //只傳一個實參,那么 x 會使用指定的實參,y z 使用的是缺省值Func(1);//傳兩個實參,那么 x y 會使用指定的實參,z 使用的是缺省值Func(1, 2);//全部都傳實參,那么 x y z 都會使用指定的實參Func(1, 2, 3);return 0;
}

運行結果:

在這里插入圖片描述

C++規定在傳實參時,不能間隔跳躍傳參,只能從左到右連續的傳,如下所示:

// 這樣傳參是錯誤的
Func(1, , 3);
Func(, 2, 3);

半缺省就是一部分的形參使用的是缺省值,且半缺省參數的缺省值得要從右往左給,不能從左往右給,也不能跳躍給缺省值,如下所示:

//半缺省函數
void Func(int x, int y = 20, int z = 30)
{cout << "x = " << x << "\ty = " << y << "\tz = " << z << endl;
}void Func(int x, int y, int z = 30)
{cout << "x = " << x << "\ty = " << y << "\tz = " << z << endl;
}

為什么必須要從右往左給形參缺省值呢?為什么不能從左往右給缺省值呢?具體原因如下所示:

void Func(int x = 10, int y = 20, int z)
{cout << "x = " << x << "\ty = " << y << "\tz = " << z << endl;
}int main()
{Func(1, 2);return 0;
}

當如上圖所示傳實參時:調用Func函數時,會產生歧義,不知道實參1和實參2的值是傳給哪個形參,很明顯實參2傳遞給形參 z 的,而實參1的值是傳遞哪個形參呢?是 x 還是 y ,這是不明確的,而從右往左給缺省值就不會存在這樣的歧義:

void Func(int x, int y = 20, int z = 30)
{cout << "x = " << x << "\ty = " << y << "\tz = " << z << endl;
}int main()
{Func(1, 2);return 0;
}

第一個實參一定是傳給第一個形參,第二個實參一定是傳給第二個形參,不會存在什么歧義問題。若是傳一個實參,那么這個實參一定是傳給函數參數列表中的第一個形參;若是傳兩個實參,那么這兩個實參一定是傳給函數的參數列表中的前兩個形參。

當函數為半缺省函數時,沒有缺省值的形參必須要有與之相對應的實參,也就是說,至少要傳一個實參。

函數的聲明與定義分離時,缺省參數不能在函數聲明和定義中同時出現,規定必須函數聲明給缺省值,缺省值不僅僅只能是具體的值,還可以是表達式。如下所示:

聲明:

在這里插入圖片描述

定義:

在這里插入圖片描述

2. 函數重載

什么是函數重載?函數重載指的是:一個函數名可以有多重的意義。C++中支持在同一作用域中出現同名函數,但是要求這些同名函數的形參不同,而C語言不支持。

int Add(int x, int y)
{return x + y;
}double Add(double x, double y)
{return x + y;
}short Add(short x, short y)
{return x + y;
}//……………………

這里的參數不同可以是參數的數據類型不同,參數的個數不同,參數的順序不同,如下所示:

//以下兩個 Add 函數構成函數重載 —— 參數類型不同
int Add(int x, int y)
{return x + y;
}double Add(double x, double y)
{return x + y;
}//以下兩個 Add 函數構成函數重載 —— 參數個數不同
short Add(short x, short y)
{return x + y;
}short Add(short x, short y, short z)
{return x + y + z;
}//以下兩個 Add 函數構成函數重載 —— 參數順序不同
long Add(int x, long y)
{return x + y;
}int Add(long x, int y)
{return x + y;
}

但是有時構成重載的兩個函數在被調用時會產生歧義,如下代碼所示:

//以下兩個 Func 函數構成函數重載 —— 參數的個數不同
void Func()
{cout << "Func( )" << endl;
}void Func(int n = 4)
{cout << "Func( int n )" << endl;
}

若是傳參調用 Func 函數,調用的一定是第二個 Func 函數;若是不傳參調用,那會調用哪個函數?其實這兩個函數都會調用,因為無參的函數既可以調用本就是無參的函數,也可以調用全缺省函數。這時代碼就會報錯,解決方法是不要將這兩個函數同時寫,用第二個函數去替代。

注意:函數的返回值類型不同不能作為函數重載的條件,因為返回值可以不被接收。

3. 引用

3.1 引用的基礎知識

引用的概念:引用不是新定義一個變量,而是給已存在的變量取了一個別名。引用的定義:類型& 引用別名 = 引用對象。如下所示:

// ra 就是 a 的別名
int a = 10;
int& ra = a;

編譯器不會為引用變量開辟內存空間,引用變量和引用對象共用同一塊內存空間:

在這里插入圖片描述
由此圖就可以得知引用變量與引用對象指向的是同一塊內存空間,ra 和 a 的地址都是一樣的,且變量的值也是一樣的。

對引用變量操作還會改變其引用對象,如下所示:

在這里插入圖片描述
ra 和 a 的值都被改變了。

此外也可以對同一個變量取多個別名,也可以對別名取別名,如下所示:

在這里插入圖片描述
它們的值是一樣的,地址也是一樣的。

在引用中尤其要注意以下的代碼:

int x = 20;
int& rx = x;
int y = 30;
rx = y;

請問這里的 rx = y 是在給 y 取別名嗎?而 y 的別名是 rx 嗎?其實并不是,這里只是將 y 的值賦值給了 rx ,修改了 rx 和 x 的值,來看一下調試窗口:

在這里插入圖片描述
這里就說明了引用不會改變指向,只要它是一個變量的引用,那么它永遠都是那個變量的別名,沒有語法能改變引用的指向C++為了區分引用與取地址,只有&跟在類型的后面才稱之為引用,單獨一個&是取地址操作符,對變量執行取地址操作

根據上述的分析,總結出引用的特性:

1. 引用在定義時必須初始化
2. 一個變量可以有多個引用
3. 引用一旦引用一個實體,就不能再引用其它實體了

3.2 引用的作用

在C語言中,若想要交換兩個變量的值,需要將這兩個變量的地址傳給形參,如此才能完成兩個變量值的交換;但是在C++中,可以使用引用,如下所示:

// rx 是 x 的別名,ry 是 y 的別名
void Swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
}int main()
{int x = 10;int y = 20;cout << "交換前:x = " << x << "\ty = " << y << endl;Swap(x, y);cout << "交換后:x = " << x << "\ty = " << y << endl;return 0;
}

運行結果:

在這里插入圖片描述

由此可以得出引用的功能:做函數的參數,修改形參影響實參

在C語言中,使用傳值傳參時,若實參的內存很大,那么往往會改為傳址傳參,因為這里會涉及拷貝問題;但是在C++中,可以使用引用,如下所示:

struct Test
{int arr[100000];int size = 0;int capacity = 0;
};// rtst 是 tst 的別名
void Func(struct Test& rtst)
{}int main()
{Test tst;Func(tst);return 0;
}

由此可以得出引用的功能:做函數的參數,減少拷貝,提高效率

既然可以給整型變量取別名,那可不可以給指針變量取別名呢?當然可以。在C語言中,若想交換兩個指針的內容,可以將指針的地址傳給形參,也就是使用二級指針;在C++中,可以使用引用來解決這個問題:

void Swap(int*& rpx, int*& rpy)
{int* tmp = rpx;rpx = rpy;rpy = tmp;
}int main()
{int x = 10;int y = 20;int* px = &x;int* py = &y;cout << "交換前:px = " << px << "\tpy = " << py << endl;Swap(px, py);cout << "交換后:px = " << px << "\tpy = " << py << endl;return 0;
}

運行結果:

在這里插入圖片描述
若想要修改函數的返回值該怎么做呢?可以使用傳引用返回,那么為什么不能使用傳值返回呢?首先得要理解一個概念,只要是傳值返回,返回的都不是原來的值,都會拷貝生成一個臨時變量,返回的是這個臨時變量,下面來介紹具體原因:

在這里插入圖片描述

由此可以得出引用功能:引用作為函數的返回值,如此就可以修改返回對象;當函數的返回值的內存較大時,用引用作為函數的返回值,可以減少拷貝,提高效率

雖然引用非常的強大,但是并不是所有的函數都要用引用作為返回值,若所有的函數的返回值都用引用,那么會造成意想不到的后果,如下代碼所示:

在這里插入圖片描述

跟C語言中學的野指針一樣,這里類似于野指針,由于是引用,可以稱之為野引用
當返回的對象出作用域后未被銷毀,那么可以使用傳引用返回;若返回的對象出作用域后被銷毀了,則不可以使用傳引用返回,應該使用傳值返回

從函數棧幀的角度去考慮:

在這里插入圖片描述
所以并不是所有的函數都要用引用作為返回值,當函數變量為局部變量的時候,出了作用域該變量就銷毀了,此時返回該局部變量的別名是一個危險的行為。

3.3 const 引用

1. 若想要引用一個const 對象,那么就必須要用使用 const 引用

int main()
{int x = 10;int& rx = x;const int y = 20;const int& ry = y;return 0;
}

若這里引用 const 修飾的對象時,并沒有使用 const 引用,那么程序會報錯,這是因為這里涉及到了權限的放大 —— 原本變量 y 被 const 修飾后不能被修改,現在對 y 取別名后,就可以通過修改別名來修改變量 y ,但是 y 本身是不能被修改的,別名卻可以修改 y ,這樣是不可取的。權限是不能放大的。const 引用也可以引用普通對象,因為普通對象的訪問權限在引用過程中可以縮小,但是不能放大。如下所示:

int main()
{int x = 10;int& rx = x;const int& r = x;int& const p = x;return 0;
}

這里就涉及到了權限的縮小,之前 x 的值是可以修改的,但是現在被 const 引用修飾后,x 的值就不可以修改了,這就是權限的縮小。這里 const 寫在類型的左右邊都可以,但是一般寫在類型的左邊。

接下來根據以下代碼來回答下面的問題:

int a = 1;
int& ra = a;
int b = a;

該代碼涉及權限的放大或縮小嗎?都不涉及,只有指針和引用才涉及權限的放大與縮小,這里只是將變量 a 的值賦值給變量 b 。

2. 要注意的是類似int& rb = a * 4;double c = 3.14;int& rc = c;這樣一些場景下a * 4的結果保存在一個臨時對象中;int& rc = c也是類似的情況,在類型轉換時會將中間值用臨時對象來保存。也就是說,rb與rc引用的都是臨時對象,而C++規定臨時對象具有常性。所以在這里就涉及到了權限的放大,必須要用const引用才行

int main()
{int a = 10;int b = 20;double c = 3.14;const int& r1 = a;          //給變量取別名const int& r2 = b;          //給變量取別名const int& r3 = 30;         //給常量取別名 //將double類型的變量c的整型部分給給臨時對象const int& r4 = c;          //當表達式運算完畢后會計算出一個結果,這個結果存儲在臨時對象中//r5引用的是表達式運算的結果,也就是臨時對象const int& r5 = a * 4;  return 0;
}

之后在寫函數的參數的時候,就使用引用來作為形參,視情況考慮是否加const。當函數的參數使用const引用后,參數就可以是臨時對象了,使用 const 引用的好處是既可以接收普通變量,也可以接收 const 修飾的變量。如下代碼所示:

int main()
{int a = 10;int b = 20;double c = 3.14;const int& r1 = a;         const int& r2 = b;                         Func(r1);Func(r2);Func(10);Func(c);Func(a * 4);return 0;
}

3.4 指針與引用的關系

引用可以完全替代指針嗎?當然是不可以的。指針有一個引用做不到的事情,就是改變指向。在數據結構中是時常要改變指向的,在這方面引用就無法做到了,必須使用引用。在實踐中指針與引用相輔相承,功能有重疊性,但是各有各的特點,互相是不可替代的:

1. 語法概念上,引用是對一個對象的取別名,不會開辟空間;指針是存儲一個對象的地址,需要開辟空間
2. 引用在定義時必須要初始化,指針可以初始化也可以不初始化,但是建議初始
3. 引用在初始化時引用一個對象后,就不能再引用其它對象了,而指針可以不斷的改變其指向的對象
4. 引用可以直接訪問其指向的對象,而指針需要解引用后,訪問的才是其指向的對象
5. 指針很容易出現空指針和野指針問題,引用很少出現,引用使用起來更加的安全
6. sizeof的含義不同,引用結果為引用類型的大小,但是指針始終是地址空間的所占字節個數(32位機器平臺下是4個字節,64位機器平臺下是8個字節)

在這里插入圖片描述

底層指針與引用之間的區別:

在這里插入圖片描述
從指令匯編角度來看,引用是由指針實現的

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

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

相關文章

Rust 官方文檔:人話版翻譯指南

鑒于大部分翻譯文檔都不太會說人話&#xff0c;本專欄主要內容為 rust 程序設計語言、rust 參考手冊、std 庫 等官方文檔的中譯中。

FlySecAgent:——MCP全自動AI Agent的實戰利器

最近&#xff0c;出于對人工智能在網絡安全領域應用潛力的濃厚興趣&#xff0c;我利用閑暇時間進行了深入研究&#xff0c;并成功開發了一款小型輕量化的AI Agent安全客戶端FlySecAgent。 什么是 FlySecAgent&#xff1f; 這是一個基于大語言模型和MCP&#xff08;Model-Contr…

實戰項目5(08)

目錄 任務場景一 【r1配置】 【r2配置】 【r3配置】 ???????任務場景二 【r1配置】 【r2配置】 ???????任務場景一 按照下圖完成網絡拓撲搭建和配置 任務要求&#xff1a; 通過在路由器R1、R2和R3上配置靜態路由&#xff0c;實現網絡中各終端PC能夠正常…

基于Kubernetes的Apache Pulsar云原生架構解析與集群部署指南(下)

文章目錄 k8s安裝部署Pulsar集群前期準備版本要求 安裝 Pulsar Helm chart管理pulsarClustersBrokersTopic k8s安裝部署Pulsar集群 前期準備 版本要求 Kubernetes 集群&#xff0c;版本 1.14 或更高版本Helm v3&#xff08;3.0.2 或更高版本&#xff09;數據持久化&#xff…

C35-數組和函數開發初見

一 數組作為函數的參數 用于傳遞數組中的某一個元素→意義不大 數組名當做函數實際參數 示例 代碼 #include <stdio.h>//封裝函數PrintArr void PrintArr(int arr[3]){int i;for(i0;i<3;i){printf("%d ",arr[i]);}putchar(\n);}//主函數 int main() { …

【小沐學GIS】基于C++繪制二維瓦片地圖2D Map(QT、OpenGL、GIS)

&#x1f37a;三維數字地球系列相關文章如下&#x1f37a;&#xff1a;1【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;OpenGL、glfw、glut、GIS&#xff09;第二期3【小沐學…

idea左側項目資源管理器不見了處理

使用idea誤觸導致&#xff0c;側邊欄和功能欄沒了&#xff0c;如何打開&#xff1f; 1.打開文件&#xff08;File&#xff09; 2. 打開設置&#xff08;Settings&#xff09; 3.選擇Appearance&Behavior--->Appearance劃到最下面&#xff0c;開啟顯示工具欄和左側并排布…

[Java實戰]Spring Boot 靜態資源配置(十三)

[Java實戰]Spring Boot 靜態資源配置&#xff08;十三&#xff09; 引言 靜態資源&#xff08;如 HTML、CSS、JavaScript、圖片等&#xff09;是 Web 應用的基石。Spring Boot 通過自動化配置簡化了靜態資源管理&#xff0c;但面對復雜場景&#xff08;如多模塊項目、CDN 集成…

多模態大語言模型arxiv論文略讀(六十九)

Prompt-Aware Adapter: Towards Learning Adaptive Visual Tokens for Multimodal Large Language Models ?? 論文標題&#xff1a;Prompt-Aware Adapter: Towards Learning Adaptive Visual Tokens for Multimodal Large Language Models ?? 論文作者&#xff1a;Yue Zha…

Python 基礎語法與數據類型(七) - 函數的定義與調用 (def, return)

文章目錄 為什么要使用函數&#xff1f;函數的定義 (def)函數的調用函數參數 (Parameters vs Arguments)返回值 (return)變量作用域 (簡要了解)總結練習題練習題答案 **創作不易&#xff0c;請大家點贊加收藏&#xff0c;關注我&#xff0c;持續更新教程&#xff01;** 到目前為…

華為配置篇-RSTP/MSTP實驗

MSTP 一、簡介二、常用命令總結三、實驗 一、簡介 RSTP&#xff08;快速生成樹協議&#xff09;? RSTP&#xff08;Rapid Spanning Tree Protocol&#xff09;是 STP 的改進版本&#xff0c;基于 ??IEEE 802.1w 標準??&#xff0c;核心目標是解決傳統 STP 收斂速度慢的問…

Docker Compose 完全指南:從入門到生產實踐

Docker Compose 完全指南&#xff1a;從入門到生產實踐 1. Docker Compose 簡介與核心價值 Docker Compose 是一個用于定義和運行多容器 Docker 應用程序的工具。通過一個 YAML 文件來配置應用的服務&#xff0c;只需簡單命令就能創建和啟動所有服務。 核心優勢&#xff1a;…

Linux 離線安裝 Docker 和 Docker Compose 最新版 的完整指南

一、準備工作 1. 下載安裝包?&#xff08;需在有網絡的機器操作&#xff09;&#xff1a; Docker 引擎&#xff1a;從官方倉庫下載最新二進制包 wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.6.tgz?Docker Compose&#xff1a;下載最新二進制…

CSS: 選擇器與三大特性

標簽選擇器 標簽選擇器就是選擇一些HTML的不同標簽&#xff0c;由于它們的標簽需求不同&#xff0c;所以CSS需要設置標簽去選擇它們&#xff0c;為滿足它們的需求給予對應的屬性 基礎選擇器 標簽選擇器 <!DOCTYPE html> <head><title>HOME</title>…

鴻蒙跨平臺開發教程之Uniapp布局基礎

前兩天的文章內容對uniapp開發鴻蒙應用做了一些詳細的介紹&#xff0c;包括配置開發環境和項目結構目錄解讀&#xff0c;今天我們正式開始寫代碼。 入門新的開發語言往往從Hello World開始&#xff0c;Uniapp的初始化項目中已經寫好了一個簡單的demo&#xff0c;這里就不再贅述…

JavaSE核心知識點02面向對象編程02-08(異常處理)

&#x1f91f;致敬讀者 &#x1f7e9;感謝閱讀&#x1f7e6;笑口常開&#x1f7ea;生日快樂?早點睡覺 &#x1f4d8;博主相關 &#x1f7e7;博主信息&#x1f7e8;博客首頁&#x1f7eb;專欄推薦&#x1f7e5;活動信息 文章目錄 JavaSE核心知識點02面向對象編程02-08&#…

【JVM-GC調優】

一、預備知識 掌握GC相關的VM參數&#xff0c;會基本的空間調整掌握相關工具明白一點&#xff1a;調優跟應用、環境有關&#xff0c;沒有放之四海而皆準的法則 二、調優領域 內存鎖競爭cpu占用io 三、確定目標 【低延遲】&#xff1a;CMS、G1&#xff08;低延遲、高吞吐&a…

基于單片機的電子法頻率計

一、電子計數法測頻率原理 通過門控控制閘門開關&#xff0c;閘門時間T自己設定&#xff0c;計數器計數脈沖個數N&#xff08;也就是待測信號&#xff09;&#xff0c;N個脈沖的時間間隔為δt,倒數即為信號的頻率f,由此 δtT/N fN/T——信號頻率 根據公式&#xff0c;如果考慮…

【C/C++】跟我一起學_C++同步機制效率對比與優化策略

文章目錄 C同步機制效率對比與優化策略1 效率對比2 核心同步機制詳解與適用場景3 性能優化建議4 場景對比表5 總結 C同步機制效率對比與優化策略 多線程編程中&#xff0c;同步機制的選擇直接影響程序性能與資源利用率。 主流同步方式: 互斥鎖原子操作讀寫鎖條件變量無鎖數據…

判斷兩臺設備是否在同一局域網內的具體方法

以下是判斷兩臺設備是否在同一局域網內的具體方法&#xff1a; 1. 檢查IP地址和子網掩碼 操作步驟&#xff1a; Windows系統&#xff1a; 按 Win R 鍵&#xff0c;輸入 cmd 并回車。輸入 ipconfig&#xff0c;查看 IPv4 地址 和 子網掩碼&#xff08;如 192.168.1.5/255.255.2…