【C++入門】缺省參數 | 函數重載

目錄

4.缺省參數

4.1缺省參數的概念

4.2缺省參數分類

4.3聲明和定義分離(聲明使用缺省參數)

4.🐍聲明和定義分離到鏈接

5.函數重載

5.1函數重載的概念

5.2可執行程序的形成步驟

5.3C++支持函數重載的原理—名字修飾(name Mangling)


4.缺省參數

4.1缺省參數的概念

缺省參數是聲明或定義函數時為函數的參數指定一個缺省值。在調用該函數時,如果沒有指定實參則采用該形參的缺省值,否則使用指定的實參。缺省參數又叫默認參數。

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

4.2缺省參數分類

  • 全缺省參數
  • 半缺省參數
  • 函數在給半缺省參數,必須是從右往左連續依次給出,不能間隔跳躍。(從第一個開始)
  • 調用函數傳參:必須從左到右連續傳參,不能跳躍。(從第一個開始)
  • 形式參數是實際參數的一份臨時拷貝。
  • 缺省參數不能在函數聲明和定義中同時出現,若有聲明只能在聲明中出現。
  • 缺省值必須是常量或者全局變量。
  • C語言不支持(編譯器不支持。
//全缺省參數
void Func(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}
//半缺省參數
void Func(int a, int b = 10, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}
//給半缺省參數
#include<iostream>
using namespace std;
//半缺省參數
void Func2(int a, int b = 10, int c = 20)
void Func2(int a, int b , int c = 20)
void Func2(int a, int b, int c)
//?void Func2(int a, int b = 10, int c)
//?void Func2(int a=10, int b, int c = 20)
{cout << "a = " << a ;cout << "b = " << b ;cout << "c = " << c ;cout << endl;
}
//調用傳參
#include<iostream>
using namespace std;
//全缺省參數
void Func1(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a ;cout << "b = " << b ;cout << "c = " << c ;cout << endl;
}
int main()
{Func1(1, 2, 3);Func1(1, 2);Func1(1);Func1();//Func1(, 2, );//?return 0;
}

?

4.3聲明和定義分離(聲明使用缺省參數)

如果聲明與定義位置同時出現缺省參數,恰巧兩個位置提供的值不同,那編譯器就無法確定到底該用那個缺省值?

在聲明處給缺省參數。因為.cpp在預處理階段會展開頭文件.h。會把.h的聲明拷貝到.cpp里面。在后面編譯階段,檢查語法也不會出錯。

?//a.hvoid Func(int a = 10);//a.cppvoid Func(int a = 20)
{///
}
// 注意:如果聲明與定義位置同時有缺省參數,
//恰巧兩個位置提供的值不同,那編譯器就無法確定到底該用那個缺省值。

4.🐍聲明和定義分離到鏈接

tips:

從語法的角度:函數名就是函數的地址。

從底層的角度:函數調用的本質是call? 函數(地址)(物理空間是連續的)

地址是函數的地址。函數底層也是一堆指令。也就是函數底層指令的第一條指令的地址。

CPU執行也是執行指令。?

聲明和定義分離,編譯階段檢查語法call Func(?)里面是沒有地址的,還沒有鏈接。那編譯階段檢查語法為什么不會報錯。(前面預處理/編譯/匯編階段是各自走各自的)

  • 編譯階段:語法檢查(自定義類型/變量/函數 搜索出處)
  • 匯編階段,編譯器就只是搜索找到聲明(承諾)
  • 鏈接階段,形成了符號表。
  • 編譯器去符號表里搜索,找到函數定義(兌現承諾)
  • 編譯器把函數定義的地址放到 call Func(07FF7F71E12E4h)
  • 符號表

//"a.cpp"
#include"a.h"
void Func(int a)
{cout << a << endl;
}//"a.h"
#pragma once
#include<iostream>
using namespace std;
void Func(int a =20);//test.cpp
#include"a.h"
int main()
{Func();Func(10);return 0;
}

在編譯階段沒有找到聲明:語法錯誤?

在鏈接階段沒有找到定義:鏈接?

5.函數重載

自然語言中,一個詞可以有多重含義,人們可以通過上下文來判斷該詞真實的含義,即該詞被重載了。函數重載也就是一詞多義
比如:以前有一個笑話,國有兩個體育項目大家根本不用看,也不用擔心。一個是乒乓球,一個是男足。前者是“誰也贏不了!”,后者是“誰也贏不了!”?

5.1函數重載的概念

函數重載:是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數,這些同名函數的形參列表(參數個數 或 類型 或 類型順序)不同,常用來處理實現功能類似數據類型不同的問題。

  • C語言不允許同名函數
  • C++語言允許同名函數。
  • 要求:函數名相同,參數不同,構成函數重載。(編譯器會根據數據類型自動匹配)
  • 參數不同:
  1. 參數類型不同
  2. 參數個數不同
  3. 參數類型順序不同
#include<iostream>
using namespace std;
// 1、參數類型不同
int Add(int left, int right)
{cout << "int Add(int left, int right)" << endl;return left + right;
}
double Add(double left, double right)
{cout << "double Add(double left, double right)" << endl;return left + right;
}// 2、參數個數不同
void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}// 3、參數類型順序不同
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);return 0;
}

5.2可執行程序的形成步驟

在C/C++中,一個程序要運行起來,需要經歷以下幾個階段:預處理、編譯、匯編、鏈接。

(前面缺省參數的聲明和定義分離鋪墊過了)

?

  • 1. 實際項目通常是由多個頭文件和多個源文件構成,而通過C語言階段學習的編譯鏈接,我們可以知道,【當前a.cpp中調用了b.cpp中定義的Add函數時】,編譯后鏈接前,a.o的目標文件中沒有Add的函數地址,因為Add是在b.cpp中定義的,所以Add的地址在b.o中。那么怎么辦呢?
  • 2. 所以鏈接階段就是專門處理這種問題,鏈接器看到a.o調用Add,但是沒有Add的地址,就會到b.o的符號表中找Add的地址,然后鏈接到一起。

  • 3.面對鏈接函數的地址到括號里:call? 函數(函數地址)
  • C語言符號表:函數名 函數地址
  • C++符號表的規則:函數名且包含函數參數類型等? 函數地址(那么鏈接時,面對Add函數,鏈接器會使用哪個方式去符號表找呢?這里每個編譯器都有自己的函數名修飾規則。只要能區分開即可)(下面細講)

5.3C++支持函數重載的原理—名字修飾(name Mangling)

C語言不支持函數重載?C++如何支持函數重載?

>>>>>>>>>? ?和前面我們講到的聲明和定義分離到鏈接中鏈接步驟(符號表搜索函數地址)

>>>>>>>>>(在符號表中去搜索函數地址)這個步驟非常關鍵。

C語言沒辦法支持重載,因為同名函數沒辦法區分。而C++是通過函數修飾規則來區分,只要參數不同,修飾出來的名字就不一樣,就支持了重載。如果兩個函數函數名和參數是一樣的,返回值不同是不構成重載的,因為調用時編譯器沒辦法區分。


?【C語言】?

C語言在符號表中去搜索函數地址 >>>>只根據函數名搜索函數地址,當然C語言不支持函數重載。C語言鏈接時,直接用函數名去找地址,有同名函數,區分不開。


?【C++】

祖師爺為了C++能夠支持函數重載,于是把搜索規則改變了。C++在符號表去搜索函數地址,規則>>>>>>>>>>>>>>>>>>>函數名且包含函數參數類型等? 函數地址,支持函數重載。

這里每個編譯器都有自己的函數名修飾規則。函數名修飾規則,名字中引入參數類型,各個編譯器有自己的實現一套。(下面從windows和Linux舉例)

【windows下名字修飾規則】?

【擴展學習:C/C++函數調用約定和名字修飾規則--有興趣好奇的可以看看,里面
有對vs下函數名修飾規則講解】C/C++ 函數調用約定___declspec(dllexport) void test2();-CSDN博客

#include<iostream>
using namespace std;
int Add(int left, int right);
double Add(double left, double right);
int main()
{Add(10, 20);Add(10.1, 20.2);
}
//可以去VS上只有聲明沒有定義,此時就會報鏈接錯誤?

【Linux下名字修飾規則】

通過下面我們可以看出gcc的函數修飾后名字不變。而g++的函數修飾后變成【_Z+函數長度+函數名+類型首字母】。

  • 采用C語言編譯器編譯后結果
  • 結論:在linux下,采用gcc編譯完成后,函數名字的修飾沒有發生改變。
  • 采用C++編譯器編譯后結果
  • 結論:在linux下,采用g++編譯完成后,函數名字的修飾發生改變,編譯器將函數參
    數類型信息添加到修改后的名字中。
      #include<stdio.h>                            2 int Add(int a,int b)                 3 {                                    4     return a+b;                      5 }                                    6 void func(int a,double b,int* p)     7 {                                    8                                      9 }                                    10 int main()                           11 {                                    12     Add(1,2);                        13     func(1,2,0);                     14     return 0;                        15 }   
  • 采用C語言編譯器編譯后結果
gcc -o projectC project.c
objdump -S projectC

  • 采用C++編譯器編譯后結果
g++ -o proejctCPP project.cpp
objdump -S projectCPP(proejctCPP)

對比Linux會發現,windows下vs編譯器對函數名字修飾規則相對復雜難懂,但道理都
是類似的,我們就不做細致的研究了。?🙂感謝大家的閱讀,若有錯誤和不足,歡迎指正。

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

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

相關文章

Linux學習之信號

目錄 1.信號的概念 2.信號的產生 3.信號的保存 4.信號的捕捉 信號的其它內容&#xff1a; SIGCHLD信號 1.信號的概念 在Linux中&#xff0c;信號是一種用于進程之間通信的基本機制。它是一種異步事件通知&#xff0c;用于通知進程發生了某些事件。如下是一些常見的Linux信…

[計算機網絡]--五種IO模型和select

前言 作者&#xff1a;小蝸牛向前沖 名言&#xff1a;我可以接受失敗&#xff0c;但我不能接受放棄 如果覺的博主的文章還不錯的話&#xff0c;還請點贊&#xff0c;收藏&#xff0c;關注&#x1f440;支持博主。如果發現有問題的地方歡迎?大家在評論區指正 目錄 一、五種IO…

線性規劃問題的高斯消元法

線性規劃的算法和解方程組的方法很像,常用的方程組的解法叫做高斯消元法,對于高斯消元法的基本流程,現給定一組線性方程: 添加圖片注釋,不超過 140 字(可選) 對于給定的線性方程組,目的是將方程組中同時能夠滿足三個等式的變量x,y,z求解出來,對于高斯消元法的基本過程…

【精通Spring】基于注解管理Bean

個人名片&#xff1a; &#x1f43c;作者簡介&#xff1a;一名大三在校生&#xff0c;喜歡AI編程&#x1f38b; &#x1f43b;???個人主頁&#x1f947;&#xff1a;落798. &#x1f43c;個人WeChat&#xff1a;hmmwx53 &#x1f54a;?系列專欄&#xff1a;&#x1f5bc;?…

集智書童 | YOLO+混合注意力機制 | YOLOv5再加4.3%才可以做對手,Transformer混合設計依舊可以卷

本文來源公眾號“集智書童”&#xff0c;侵權刪&#xff0c;干貨滿滿。YOLOv5重出江湖&#xff01; 原文鏈接&#xff1a;https://mp.weixin.qq.com/s/vb7HsA0fKDgRc3uC8Z-2yw 在工業生產過程中&#xff0c;由于低效率、不統一的評估、高成本以及缺乏實時數據&#xff0c;傳統…

LeetCode //C - 32. Longest Valid Parentheses

32. Longest Valid Parentheses Given a string containing just the characters ‘(’ and ‘)’, return the length of the longest valid (well-formed) parentheses substring. Example 1: Input: s “(()” Output: 2 Explanation: The longest valid parentheses s…

【刷題1】LeetCode 994. 腐爛的橘子 java題解

tag:圖論 廣度優先搜索 https://leetcode.cn/problems/rotting-oranges/description/?envTypestudy-plan-v2&envIdtop-100-liked 使用廣度優先搜索&#xff0c;搜索步數就是分鐘數&#xff0c;等到所有橘子都腐爛后&#xff0c;各個橘子腐爛的最長分鐘數就是全部都爛的最小…

C語言-指針(上)

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、pandas是什么&#xff1f;二、使用步驟 1.引入庫2.讀入數據總結 前言 本篇文章將為大家介紹C語言中的核心內容-指針&#xff0c;指針在C語言的中知識內容比…

【文件管理】關于上傳下載文件的設計

這里主要談論的是產品設計里面的文件管理&#xff0c;比如文件的上傳交互及背后影響到的前后端設計。 上傳文件 場景&#xff1a;一條記錄&#xff0c;比如個人信息&#xff0c;有姓名&#xff0c;出生年月&#xff0c;性別等一般的字段&#xff0c;還可以允許用戶上傳附件作為…

Java 小項目開發日記 04(文章接口的開發、oss圖片上傳)

Java 小項目開發日記 04&#xff08;文章接口的開發、oss圖片上傳&#xff09; 項目目錄 配置文件&#xff08;pom.xml&#xff09; <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sc…

機器學習:集成學習(Python)

一、Adaboost算法 1.1 Adaboost分類算法 adaboost_discrete_c.py import numpy as np import copy from ch4.decision_tree_C import DecisionTreeClassifierclass AdaBoostClassifier:"""adaboost分類算法&#xff1a;既可以做二分類、也可以做多分類&#…

python常用pandas函數nlargest 和 nsmallest及其手動實現

pandas是Python數據分析的重要工具之一&#xff0c;提供了大量便捷的數據操作方法。nlargest和nsmallest是pandas中兩個非常實用的函數&#xff0c;它們可以幫助我們快速找出Series或DataFrame中最大或最小的n個值。 ### pandas中的nlargest和nsmallest函數 - nlargest(n, colu…

掌握Go語言:深入探究Go語言中的命令源碼文件與參數處理技巧(3)

在Go語言學習的路上&#xff0c;掌握命令源碼文件與參數處理技巧是至關重要的。本文將深入探討命令源碼文件的概念、作用以及參數處理的方法&#xff0c;同時結合進銷存項目&#xff0c;展示實際應用與代碼示例。 命令源碼文件的概述 命令源碼文件是Go語言程序的運行入口&…

uniapp的h5端在線預覽文件

步驟如下&#xff1a; 1、下載需要準備的工具文件包 2、將其解壓到/static/pdf文件夾下,如圖&#xff1a; 3、創建在線查看文件的頁面&#xff1a; <template><view><web-view :src"path"></web-view></view> </template>&l…

linux檢測和重啟python腳本

#!/bin/bash# 檢測Flask應用是否掛了 if ! pgrep -f "flask_app.py" >/dev/null; then# 重啟Flask應用cd /path/to/your/flask/appnohup python3 flask_app.py >/dev/null 2>&1 & fi這是一個簡單的bash腳本&#xff0c;用于檢測Flask應用是否掛掉&a…

JavaScript練手小技巧:一文看懂<script>標簽的 ansyc 和 defer

<script>標簽的 ansyc 和 defer 屬性。只對外部加載 JS 文件有效。 <script src"js/app.js" async></script> <script src"js/app.js" defer></script> 普通加載 js&#xff08;同步加載&#xff09;&#xff1a;會打斷 …

ES7、ES8、ES9、ES10、ES11、ES12 新特性匯總合集

在過去幾年里&#xff0c;ECMAScript 標準不斷更新&#xff0c;引入了許多令人激動的功能和改進。讓我們來看看從 ES7 到 ES12 各個版本帶來的重要變化&#xff1a; 1. ES7&#xff08;ECMAScript 2016&#xff09; 1. Array.prototype.includes 方法 Array.prototype.includ…

【字符串左旋右旋不會做?快來看看這篇“彈幕滾動”,你就有思路了!】

前言 不知道大家在做題時有沒有遇到過“字符串旋轉”的題目&#xff0c;很多人可能沒有思路&#xff0c;這里我不具體講解單一的題目&#xff0c;而是展現一個“彈幕滾動”的示例&#xff0c;相信大家看懂后就能做出“字符串旋轉”的題了&#xff01; 技術名詞解釋 1.什么是“…

關于決策樹模型

決策樹模型是一種常用的數據挖掘方法&#xff0c;它通過模擬人類決策過程來對數據進行分類或回歸分析。決策樹由節點和邊組成&#xff0c;其中每個內部節點代表一個屬性上的測試&#xff0c;每個分支代表測試的一個結果&#xff0c;而每個葉節點&#xff08;樹的末端&#xff0…

Vue3 isProxy,isReactive,isReadonly 三者解析

1、isProxy 作用&#xff1a;判斷當前數據是否為代理數據。 注意&#xff1a;它只對通過 reactive&#xff0c;readonly&#xff0c;shallowReactive&#xff0c;shallowReadonly 這四個方法包裹的數據返回true&#xff0c;對于 ref 以及通過 new Proxy 代理的數據返回都是fal…