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

深入了解C++函數(shù)重載解析策略

 更新時間:2022年10月20日 08:18:52   作者:木三百川  
這篇文章主要為大家詳細介紹了C++中函數(shù)重載的解析策略,文中的示例代碼講解詳細,對我們學(xué)習(xí)C++有一定幫助,感興趣的小伙伴可以了解一下

參考《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,張海龍 袁國忠譯,人民郵電出版社。C++ 使用重載解析策略來決定為函數(shù)調(diào)用使用哪一個函數(shù)定義。重載解析過程大致分為如下三步:

第 1 步:創(chuàng)建候選函數(shù)列表,只要求函數(shù)名一樣即可,對函數(shù)特征標以及是否為模板函數(shù)無要求;

第 2 步:在上一步的基礎(chǔ)上創(chuàng)建可行函數(shù)列表,包含特征標完全匹配的常規(guī)函數(shù)或模板函數(shù)、以及實參隱式轉(zhuǎn)換后完全匹配的常規(guī)函數(shù)或模板函數(shù),這些都是參數(shù)數(shù)目正確的函數(shù);

第 3 步:在上一步的基礎(chǔ)上確定最佳匹配函數(shù),若有則使用它,若沒有則該函數(shù)調(diào)用失敗。

下面以一個例子來說明這個重載過程:

//全部函數(shù)原型
void may(int);                        //原型#1
float may(float, float = 3);          //原型#2
void may(char);                       //原型#3
char * may(const char *);             //原型#4
char may(const char &);               //原型#5
template<class T> void may(const T &);//原型#6
template<class T> void may(T *);      //原型#7
void may(char, double);               //原型#8
void mbk(float);                      //原型#9
char mkk(int, char);                  //原型#10
int mck(char);                        //原型#11
double myk(float);                    //原型#12
void mpk(char);                       //原型#13
 
//函數(shù)調(diào)用
may('B');
 
//函數(shù)定義
...

重載第 1 步:創(chuàng)建候選函數(shù)列表。即函數(shù)名稱為 may 的常規(guī)函數(shù)和模板函數(shù),候選函數(shù)列表如下:

//重載第1步:創(chuàng)建候選函數(shù)列表
void may(int);                        //原型#1
float may(float, float = 3);          //原型#2
void may(char);                       //原型#3
char * may(const char *);             //原型#4
char may(const char &);               //原型#5
template<class T> void may(const T &);//原型#6
template<class T> void may(T *);      //原型#7
void may(char, double);               //原型#8

重載第 2 步:創(chuàng)建可行函數(shù)列表。由于整數(shù)類型 char 不能被隱式地轉(zhuǎn)換為指針類型 char *,因此函數(shù) #4 和函數(shù) #7 都被排除,而函數(shù) #8 因為參數(shù)數(shù)目不匹配也會被排除。進行完全匹配時,C++ 允許下表這些無關(guān)緊要的轉(zhuǎn)換,表中 Type 表示任意類型,例如 char & 到 const char & 的轉(zhuǎn)換也包含在內(nèi),表中 Type (argument-list) 意味著用作實參的函數(shù)名和用作形參的函數(shù)指針只要返回類型和參數(shù)列表相同,就是匹配的。

實參類型形參類型
TypeType &
Type &Type
Type []Type *
Type (argument-list)Type (*) (argument-list)
Typeconst Type
Typevolatile Type
Type *const Type *
Type *volatile Type *

根據(jù)此表可知,剩下的函數(shù)中包含特征標完全匹配的常規(guī)函數(shù) #3 和 #5、特征標完全匹配的模板函數(shù) #6(此時 T 可以被實例化為 char)、實參隱式轉(zhuǎn)換后完全匹配的常規(guī)函數(shù) #1 和 #2??尚泻瘮?shù)列表如下:

//重載第2步:創(chuàng)建可行函數(shù)列表
void may(int);                        //原型#1
float may(float, float = 3);          //原型#2
void may(char);                       //原型#3
char may(const char &);               //原型#5
template<class T> void may(const T &);//原型#6

重載第 3 步:確定最佳匹配函數(shù)。通常,從最佳到最差的順序如下所述:

  • 特征標完全匹配;
  • 類型需經(jīng)隱式提升轉(zhuǎn)換,例如 char 和 short 自動轉(zhuǎn)換為 int,float 自動轉(zhuǎn)換為 double;
  • 類型需經(jīng)隱式標準轉(zhuǎn)換,例如 int 轉(zhuǎn)換為 char,long 轉(zhuǎn)換為 double;
  • 類型需經(jīng)隱式自定義轉(zhuǎn)換,例如類中用戶定義的類型轉(zhuǎn)換。

依此規(guī)則,函數(shù) #3 和函數(shù) #5、函數(shù) #6 都是特征標完全匹配的最佳匹配函數(shù),函數(shù) #1 需經(jīng)隱式提升轉(zhuǎn)換,函數(shù) #2 需經(jīng)隱式標準轉(zhuǎn)換,由此各函數(shù)最佳匹配程度為:(#3, #5, #6) > #1 > #2。當特征標完全匹配時,又有如下規(guī)則:

  • 指向非 const 數(shù)據(jù)的指針和引用優(yōu)先與形參為非 const 指針和引用的函數(shù)匹配;
  • 優(yōu)先與非模板函數(shù)匹配;
  • 同為模板函數(shù)時,優(yōu)先與較具體的模板函數(shù)匹配。

依此規(guī)則,非模板函數(shù) #3 和 #5 最佳匹配程度要高于模板函數(shù) #6 ,即各函數(shù)最佳匹配程度為:(#3, #5) > #6 > #1 > #2。最終出現(xiàn)了兩個最佳匹配函數(shù) #3 和 #5 ,因此該函數(shù)調(diào)用失敗,編譯器將報錯。

//重載第 3 步:確定最佳匹配函數(shù)
void may(char);                       //原型#3
char may(const char &);               //原型#5

下面展開來說上述幾條完全匹配時的規(guī)則。

第 1 條:指向非 const 數(shù)據(jù)的指針和引用優(yōu)先與形參為非 const 指針和引用的函數(shù)匹配,這一點需明確,const 和非 const 之間的區(qū)別只適用于指針和引用。下面 4 個函數(shù)都與函數(shù)調(diào)用是完全匹配的:

//函數(shù)原型
void recycle(int);        //原型#1
void recycle(const int);  //原型#2
void recycle(int &);      //原型#3
void recycle(const int &);//原型#4
 
//函數(shù)調(diào)用
int x = 5;
recycle(x);
 
//函數(shù)定義
...
  • 如果這 4 個函數(shù)同時存在,則無法完成重載,編譯器會報多義性匹配的錯誤;
  • 如果只存在函數(shù) #1 與 #2,則無法完成重載,編譯器會報重復(fù)定義的錯誤;
  • 如果只存在函數(shù) #1 與 #3,則無法完成重載,編譯器會報多義性匹配的錯誤;
  • 如果只存在函數(shù) #1 與 #4,則無法完成重載,編譯器會報多義性匹配的錯誤;
  • 如果只存在函數(shù) #2 與 #3,則無法完成重載,編譯器會報多義性匹配的錯誤;
  • 如果只存在函數(shù) #2 與 #4,則無法完成重載,編譯器會報多義性匹配的錯誤;
  • 如果只存在函數(shù) #3 與 #4,則函數(shù)調(diào)用時編譯器將會選擇 #3。

第 2 條:優(yōu)先與非模板函數(shù)匹配,這一點比較簡單,當完全匹配的函數(shù)中,一個是非模板函數(shù),另一個是模板函數(shù)時,非模板函數(shù)將優(yōu)于模板函數(shù),顯式具體化、顯式實例化、隱式實例化都屬于模板函數(shù)。

第 3 條:同為模板函數(shù)時,優(yōu)先與較具體的模板函數(shù)匹配,找出最具體的模板的規(guī)則被稱為函數(shù)模板的部分排序規(guī)則(partial ordering rules)。這意味著顯式具體化優(yōu)先于常規(guī)模板函數(shù),都為常規(guī)模板函數(shù)時,編譯器優(yōu)先選擇實例化時類型轉(zhuǎn)換更少的那一個。以下面的程序為例,調(diào)用方式 recycle(&ink) 既與模板 #1 匹配,此時 Type 將被解釋為 blot *,也與模板 #2 匹配,此時 Type 將被解釋為 blot,因此將這兩個隱式實例 recycle<blot *>(blot *) 和 recycle<blot>(blot *) 發(fā)送到可行函數(shù)池中。在選擇最佳匹配函數(shù)時,#2 被認為是更具體的,因為它已經(jīng)顯式地指出,函數(shù)參數(shù)是指向 Type 的指針,相比于 #1,它對類型的要求更加地具體,在生成過程中所需要的轉(zhuǎn)換更少,因此調(diào)用方式 recycle(&ink) 實際會匹配版本 #2。

//兩個常規(guī)模板函數(shù)
template <class Type> void recycle(Type t);   //原型#1
template <class Type> void recycle(Type * t); //原型#2
 
//調(diào)用程序包含如下代碼
struct blot {int a; char b[10];};
blot ink = {25, "spots"};
...
recycle(&ink);  //使用版本#2
 
//函數(shù)定義
...

部分排序規(guī)則的另一個示例程序如下,它與上一個例子有異曲同工之妙。由于模板 #2 做了特定的假設(shè):數(shù)組內(nèi)容是指針,對類型的要求更加地具體,因此在調(diào)用時第一個參數(shù)若傳入指針數(shù)組 pt,則將實際匹配函數(shù) #2。

//兩個常規(guī)模板函數(shù)
template <typename T> 
void ShowArray(T arr[], int n);   //原型#1
template <typename T> 
void ShowArray(T * arr[], int n); //原型#2
 
//調(diào)用程序包含如下代碼
int things[6] = {13, 31, 103, 301, 310, 130};
int * pt[3] = {&things[0], &things[2], &things[4]};
ShowArray(things, 6);  //使用版本#1
ShowArray(pt, 3);      //使用版本#2
 
//函數(shù)定義
...

將有多個參數(shù)的函數(shù)調(diào)用與有多個參數(shù)的原型進行匹配時,編譯器必須考慮所有參數(shù)的匹配情況。如果找到比其他可行函數(shù)都合適的函數(shù),則選擇該函數(shù)。一個函數(shù)要比其他函數(shù)都合適,其所有參數(shù)的匹配程度都必須不比其他函數(shù)差,同時至少有一個參數(shù)的匹配程度比其他函數(shù)都高。

在有些情況下,可通過編寫合適的函數(shù)調(diào)用,來引導(dǎo)編譯器做出程序員期望的選擇。如下所示,其中模板函數(shù)返回兩個值中較小的一個,非模板函數(shù)返回兩個值中絕對值較小的那個。第一次調(diào)用時根據(jù)重載解析策略選擇了非模板函數(shù) #2;第二次調(diào)用時根據(jù)重載解析策略選擇了模板函數(shù) #1 的 double 版本,屬于模板函數(shù)的隱式實例化;第三次調(diào)用的 <> 指出,編譯器應(yīng)該選擇模板函數(shù),此時編譯器會查看調(diào)用函數(shù)時的實參類型來進行實例化,也屬于模板函數(shù)的隱式實例化;第四次調(diào)用的 <int> 顯式指出,編譯器應(yīng)該使用模板函數(shù)的 int 實例化版本,此時屬于模板函數(shù)的顯式實例化。

#include <iostream>
 
//函數(shù)#1
template<class T>
T lesser(T a, T b)
{
    return a < b ? a : b;
}
 
//函數(shù)#2
int lesser(int a, int b)
{
    a = a < 0 ? -a : a;
    b = b < 0 ? -b : b;
    return a < b ? a : b;
}
 
//函數(shù)調(diào)用
int main()
{
    using namespace std;
    
    int m = 20;
    int n = -30;
    double x = 15.5;
    double y = 25.9;
    
    //使用#2,結(jié)果為20
    cout << lesser(m, n) << endl;
    
    //使用#1,double隱式實例化,結(jié)果為15.5
    cout << lesser(x, y) << endl;
    
    //使用#1,int隱式實例化,結(jié)果為-30
    cout << lesser<>(m, n) << endl;
    
    //使用#1,int顯式實例化,結(jié)果為15
    cout << lesser<int>(x, y) << endl;
    
    return 0;
}

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

相關(guān)文章

最新評論