欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++深入淺出講解函數(shù)重載

 更新時(shí)間:2022年05月31日 09:57:04   作者:格式化、、  
C++允許多個(gè)函數(shù)擁有相同的名字,只要它們的參數(shù)列表不同就可以,這就是函數(shù)的重載(Function?Overloading),借助重載,一個(gè)函數(shù)名可以有多種用途

前言

自然語(yǔ)言中,一個(gè)詞可以有多重含義,人們可以通過(guò)上下文來(lái)判斷該詞真實(shí)的含義,即該詞被重載了。

比如:以前有一個(gè)笑話,國(guó)有兩個(gè)體育項(xiàng)目大家根本不用看,也不用擔(dān)心。一個(gè)是乒乓球,一個(gè)是男足。前者是“誰(shuí)也贏不了!”,后者是“誰(shuí)也贏不了!”

函數(shù)重載

1.1 函數(shù)重載的概念

函數(shù)重載:

  1. 它是函數(shù)的一種特殊情況,C++允許在同一作用域中同一作用域中聲明幾個(gè)功能類(lèi)似的同名函數(shù)
  2. 函數(shù)重載的關(guān)鍵是函數(shù)的參數(shù)列表,也稱(chēng)為“函數(shù)特征標(biāo)”
  3. 這些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù)、類(lèi)型和順序(不同類(lèi)型的順序))必須不同,常用來(lái)處理實(shí)現(xiàn)功能類(lèi)似數(shù)據(jù)類(lèi)型不同的問(wèn)題
  4. 函數(shù)重載也是多態(tài)的一種,多態(tài)指的是“有多種形式”
//C語(yǔ)言不支持重載,C++支持重載
int Add(int left, int right)
{
   return left+right;
}
double Add(double left, double right)
{
   return left+right;
}
int Add(int left, double right)
{
   return left+right;
}
int Add(double left, int right)
{
   return left+right;
}
int main()
{
   Add(10, 20);
   Add(10.0, 20.0);
   Add(10, 20.0);
   Add(10.0, 20.0)
   return 0;
}

下面兩個(gè)函數(shù)屬于函數(shù)重載嗎?

short Add(short left, short right)
{
   return left+right;
}
int Add(short left, short right)
{
   return left+right;
}
int main()
{
   Add(10, 20);
   Add(10, 20);
   return 0;
}

代碼解析:

  1. 上述代碼中的兩個(gè)函數(shù)不屬于函數(shù)重載
  2. 因?yàn)橹剌d的形參列表(參數(shù)個(gè)數(shù)、類(lèi)型和順序)必須不同
  3. 函數(shù)重載與函數(shù)返回值的類(lèi)型無(wú)關(guān),并且在函數(shù)調(diào)用時(shí),也是無(wú)法識(shí)別它的

1.2 函數(shù)重載的意義

意義:

在C語(yǔ)言中,想要定義多個(gè)不同類(lèi)型交換數(shù)據(jù)的子函數(shù),需要不同的函數(shù)名來(lái)命名,比如SweapA、SweapB…等等

void SweapA(int *pa, int *pb)
{
   int temp = *pa;
   *pa = *pb;
   *pb = temp;
}
void SweapB(double *pa, double *pb)
{
   double temp = *pa;
   *pa = *pb;
   *pb = temp;
}
int main()
{
   int a = 10, b = 20;
   double c = 10.0, d = 20.0;
   SweapA(&a, &b);
   SweapB(&c), &d);
   return 0;
}
  1. 但是,在C++中,通過(guò)函數(shù)重載,只需要命名一次就可以了
  2. 雖然跟C語(yǔ)言一樣要重復(fù)定義函數(shù),但是后面會(huì)學(xué)到函數(shù)模板后,可以很好的解決這個(gè)重復(fù)定義問(wèn)題
void Sweap(int *pa, int *pb)
{
   int temp = *pa;
   *pa = *pb;
   *pb = temp;
}
void Sweap(double *pa, double *pb)
{
   double temp = *pa;
   *pa = *pb;
   *pb = temp;
}
int main()
{
   int a = 10, b = 20;
   double c = 10.0, d = 20.0;
   Sweap(&a, &b);
   Sweap(&c), &d);
   return 0;
}

1.3 名字修飾(name Mangling)

名字修飾(name Mangling):

  • C++為了跟蹤每一個(gè)重載函數(shù),它都會(huì)給這些函數(shù)指定一個(gè)私密身份
  • 使用C++編譯器編寫(xiě)函數(shù)重載程序時(shí),C++編譯器將執(zhí)行一些奇特的操作 — — ---名稱(chēng)修飾 或 名稱(chēng)矯正
  • 它根據(jù)函數(shù)原型中指定的形參對(duì)每個(gè)函數(shù)名進(jìn)行加密
  • 對(duì)參數(shù)數(shù)目和類(lèi)型進(jìn)行編碼,添加的一組符號(hào)符合隨函數(shù)形參列表而異,修飾時(shí)使用的約定(函數(shù)名)隨編譯器而異

為什么C++支持重載,而C語(yǔ)言不支持呢?

  • 在C/C++中,一個(gè)程序要運(yùn)行起來(lái),需要經(jīng)歷以下幾個(gè)階段:預(yù)處理、編譯、匯編、鏈接
  • 預(yù)處理(.i):文件展開(kāi)、宏替換、條件編譯、去注釋
  • 編譯(.s):檢查語(yǔ)法是否正確,生成匯編代碼
  • 匯編(.o):將匯編代碼轉(zhuǎn)化成二進(jìn)制的機(jī)器碼
  • 鏈接(a.out):生成符號(hào)表,找調(diào)用函數(shù)的地址,鏈接匹配,合并到一起

  • 實(shí)際我們的項(xiàng)目通常是由多個(gè)頭文件和多個(gè)源文件構(gòu)成,當(dāng)前a.cpp中調(diào)用了b.cpp中定義的Add函數(shù)
  • 在編譯后鏈接前的處理階段,a.o的目標(biāo)文件中沒(méi)有Add的函數(shù)地址,因?yàn)锳dd是在b.cpp中定義的,所以Add的地址在b.o中。那么怎么辦呢?
  • 鏈接器看到a.o調(diào)用Add,但是沒(méi)有Add的地址,就會(huì)到b.o的符號(hào)表中找Add的地址,然后鏈接到一起
  • 鏈接時(shí),面對(duì)Add函數(shù),鏈接器會(huì)使用哪個(gè)名字去找呢?這里每個(gè)編譯器都有自己的函數(shù)名修飾規(guī)則

在Linux下使用gcc和g++編譯器演示函數(shù)名被修飾后的名字

采用C語(yǔ)言編譯器編譯后結(jié)果(反匯編)

結(jié)論:在Linux下,采用gcc編譯完成后,函數(shù)名字的修飾沒(méi)有發(fā)生改變

采用C++編譯器編譯后結(jié)果(反匯編)

結(jié)論:在Linux下,采用g++編譯完成后,函數(shù)名字的修飾發(fā)生改變,編譯器將函數(shù)參數(shù)類(lèi)型信息添加到修改后的名字中

總結(jié)

gcc的函數(shù)修飾后名字不變。而g++的函數(shù)修飾后變成(_Z+函數(shù)長(zhǎng)度+函數(shù)名+類(lèi)型首字母)

C語(yǔ)言沒(méi)辦法支持重載,因?yàn)橥瘮?shù)沒(méi)辦法區(qū)分。而C++是通過(guò)函數(shù)修飾規(guī)則來(lái)區(qū)分,只要參數(shù)不同,修飾出來(lái)的名字就不一樣,就支持了重載

Windows下名字修飾規(guī)則

結(jié)論:對(duì)比Linux會(huì)發(fā)現(xiàn),windows下C++編譯器對(duì)函數(shù)名字修飾非常奇怪,但道理都是一樣的

擴(kuò)展學(xué)習(xí):C/C++函數(shù)調(diào)用約定和名字修飾規(guī)則

C++函數(shù)重載

C/C++的調(diào)用約定

接下來(lái),再演示一個(gè)例子

f.h
#include <stdio.h>

void f(int a, double b);
void f(double b, int a);

f.cpp
#include "f.h"

void f(int a, double b);
{
   printf("%d %lf\n", a, b)
}

void f(double b, int a);
{
   printf("%lf %d\n", b, a)
}
Test.cpp
#include "f.h"

int main()
{
   f(1, 2.222);
   f(2.222, 1);
   return 0;
}

編譯后,生成匯編指令;鏈接時(shí),生成符號(hào)表

Linux下g++(C++)編譯器的命名:

Linux下gcc(C)編譯器的命名:

1.4 extern "C"

  • 有時(shí)候在C++工程中可能需要將某些函數(shù)按照C的風(fēng)格來(lái)編譯
  • 但是,大多數(shù)情況下是C工程需要將某些函數(shù)按照C++的風(fēng)格來(lái)編譯
  • C可以調(diào)用CPP的靜態(tài)/動(dòng)態(tài)庫(kù),而CPP也可以調(diào)用C的靜態(tài)/動(dòng)態(tài)庫(kù)
  • extern “C”是告訴編譯器,它所聲明的函數(shù),是C的庫(kù),要用C的鏈接方式去調(diào)用靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)

那么CPP是怎么調(diào)用C中的靜態(tài)/動(dòng)態(tài)庫(kù)呢?(vs2022演示)

首先,我們用C來(lái)生成一個(gè)靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)

Test.h
#include <stdio.h>
void PrintArray(int* p, int n); //顯示數(shù)組內(nèi)容
void InsertSort(int* p, int n); //插入排序
Test.C
#include "Test.h"
void InsertSort(int* p, int n)
{
    for (int i = 0; i < n - 1; ++i)
    {
        int end = i;
        int tmp = p[end + 1];
        while (end >= 0)
        {
            if (tmp < p[end])
            {
                p[end + 1] = p[end];
                --end;
            }
            else
            {
                break;
            }
        }
        p[end + 1] = tmp;
    }
}

配置類(lèi)型改成靜態(tài)庫(kù)后,生成解決方案,就得到后綴.lib文件了

在CPP項(xiàng)目中添加新的庫(kù)目錄(這個(gè)庫(kù)是你生成的靜態(tài)庫(kù)的路徑)

增加新的依賴(lài)項(xiàng)(依賴(lài)項(xiàng)為生成靜態(tài)庫(kù)的文件名+后綴"Test.lib")

做完這些準(zhǔn)備后,我們來(lái)進(jìn)行編譯程序

  • 編譯后我們發(fā)現(xiàn)鏈接階段時(shí)出現(xiàn)了錯(cuò)誤
  • 原因是:C++調(diào)用C時(shí),它們之間的函數(shù)命名規(guī)則(名稱(chēng)修飾)不同
  • 我們需要C++中的extern "C"來(lái)解決
  • extern “C”是告訴編譯器,它所聲明的函數(shù),是C的庫(kù),要用C的鏈接方式去調(diào)用靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)
extern "C"
{
    //"../"是在當(dāng)前目錄的上一個(gè)目錄中找文件
    #include "../../Test/Test/Test.h"
}
#include <iostream>
using namespace std;
void TestInsertSort()
{
	int Array[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	InsertSort(Array, sizeof(Array) / sizeof(Array[0]));
	for (int i = 0; i < 10; ++i)
		cout << Array[i] << " ";
	cout << " " << endl;
}
int main()
{
	TestInsertSort();
	return 0;
}

如果C想調(diào)用CPP的靜態(tài)或動(dòng)態(tài)庫(kù)呢?

  • C調(diào)用CPP庫(kù)時(shí),也會(huì)遇到名稱(chēng)修飾的問(wèn)題
  • 這里需要對(duì)CPP的名稱(chēng)修飾規(guī)則改成C的規(guī)則
  • 這里我們需要用到"條件編譯"來(lái)解決問(wèn)題
Test.h
#include <stdio.h>
#ifdef __cplusplus
      #define EXTERN_C extern "C"
#else 
      #define EXTERN_C
#endif
EXTERN_C void PrintArray(int* p, int n);
EXTERN_C void InsertSort(int* p, int n);
Test.cpp
#include "Test.h"
void PrintArray(int* p, int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%d ", p[i]);
    }
    printf("\n");
}
void InsertSort(int* p, int n)
{
    for (int i = 0; i < n - 1; ++i)
    {
        int end = i;
        int tmp = p[end + 1];
        while (end >= 0)
        {
            if (tmp < p[end])
            {
                p[end + 1] = p[end];
                --end;
            }
            else
            {
                break;
            }
        }
        p[end + 1] = tmp;
    }
}

感謝大家支持?。?!

到此這篇關(guān)于C++深入淺出講解函數(shù)重載的文章就介紹到這了,更多相關(guān)C++函數(shù)重載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言進(jìn)階:指針的進(jìn)階(4)

    C語(yǔ)言進(jìn)階:指針的進(jìn)階(4)

    這篇文章主要介紹了C語(yǔ)言指針詳解及用法示例,介紹了其相關(guān)概念,然后分享了幾種用法,具有一定參考價(jià)值。需要的朋友可以了解下
    2021-09-09
  • C語(yǔ)言數(shù)據(jù)的存儲(chǔ)超詳細(xì)講解中篇練習(xí)

    C語(yǔ)言數(shù)據(jù)的存儲(chǔ)超詳細(xì)講解中篇練習(xí)

    使用編程語(yǔ)言進(jìn)行編程時(shí),需要用到各種變量來(lái)存儲(chǔ)各種信息。變量保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。您可能需要存儲(chǔ)各種數(shù)據(jù)類(lèi)型的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類(lèi)型,來(lái)分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么
    2022-04-04
  • c++代碼調(diào)試方式的幾點(diǎn)建議

    c++代碼調(diào)試方式的幾點(diǎn)建議

    這篇文章主要介紹了c++代碼調(diào)試方式的幾點(diǎn)建議,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-08-08
  • 基于C語(yǔ)言實(shí)現(xiàn)2048游戲

    基于C語(yǔ)言實(shí)現(xiàn)2048游戲

    這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)2048游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C語(yǔ)言進(jìn)階可變參數(shù)列表

    C語(yǔ)言進(jìn)階可變參數(shù)列表

    這篇文章主要為大家介紹了C語(yǔ)言進(jìn)階可變參數(shù)列表的示例詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • C語(yǔ)言實(shí)現(xiàn)按行讀寫(xiě)文件

    C語(yǔ)言實(shí)現(xiàn)按行讀寫(xiě)文件

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)按行讀寫(xiě)文件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • 詳解C++虛函數(shù)的工作原理

    詳解C++虛函數(shù)的工作原理

    這篇文章主要介紹了C++虛函數(shù)的工作原理的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Qt兩種定時(shí)器使用實(shí)現(xiàn)方式

    Qt兩種定時(shí)器使用實(shí)現(xiàn)方式

    這篇文章主要給大家介紹了關(guān)于Qt兩種定時(shí)器使用實(shí)現(xiàn)方式的相關(guān)資料,Qt中的定時(shí)器類(lèi)是QTimer,QTimer不是一個(gè)可見(jiàn)的界面組件,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • C++多線程傳參的實(shí)現(xiàn)方法

    C++多線程傳參的實(shí)現(xiàn)方法

    本文主要介紹了C++多線程傳參的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • vs code 配置c/c++環(huán)境的詳細(xì)教程(推薦)

    vs code 配置c/c++環(huán)境的詳細(xì)教程(推薦)

    這篇文章主要介紹了vs code 配置c/c++環(huán)境的詳細(xì)教程(推薦),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評(píng)論