C++中的函式過載中為什麼不考慮返回值型別?
1. 問題描述
函式過載是指在同一作用域內,可以有一組具有相同函式名,不同引數列表的函式,這組函式被稱為過載函式。那為什麼不可以是函式名相同,引數列表相同,函式的返回值不同呢?
2. 從一個函式過載例項說起
看下面的一個例子,來體會一下:實現一個列印函式,既可以列印int型、也可以列印字串型。在C++中,我們可以這樣做:
通過上面程式碼的實現,可以根據具體的print()的引數去呼叫print(int)還是print(string)。上面print(12)會去呼叫print(int),print("hello world")會去呼叫print(string)#include<iostream> using namespace std; void print(int i) { cout<<"print a integer :"<<i<<endl; } void print(string str) { cout<<"print a string :"<<str<<endl; } int main() { print(12); print("hello world!"); return 0; }
3. 為什麼需要函式過載(why)?
- 試想如果沒有函式過載機制,如在C中,你必須要這樣去做:為這個print函式取不同的名字,如print_int、print_string。這裡還只是兩個的情況,如果是很多個的話,就需要為實現同一個功能的函式取很多個名字,如加入列印long型、char*、各種型別的陣列等等。這樣做很不友好!
- 類的建構函式跟類名相同,也就是說:建構函式都同名。如果沒有函式過載機制,要想例項化不同的物件,那是相當的麻煩!
- 操作符過載,本質上就是函式過載,它大大豐富了已有操作符的含義,方便使用,如+可用於連線字串等!
通過上面的介紹我們對函式過載,應該喚醒了我們對函式過載的大概記憶。下面我們就來分析,C++是如何實現函式過載機制的
4. 函式過載為什麼不考慮返回值型別
為了弄清楚這個問題,我們先看看宣告/定義過載函式時,是如何解決命名衝突的?
為了瞭解編譯器是如何處理這些過載函式的,我們反編譯下上面我們生成的執行檔案,看下彙編程式碼(全文都是在Linux下面做的實驗,Windows類似,你也可以參考《一道簡單的題目引發的思考》一文,那裡既用到Linux下面的反彙編和Windows下面的反彙編,並註明了Linux和Windows組合語言的區別)。我們執行命令objdump -d a.out >log.txt
發現函式void print(int i) 編譯之後為:(注意它的函式簽名變為——_Z5printi)
發現函式void print(string
str) 編譯之後為:(注意它的函式簽名變為——_Z5printSs)
我們可以發現編譯之後,過載函式的名字變了不再都是print!這樣不存在命名衝突的問題了,但又有新的問題了——變名機制是怎樣的,即如何將一個過載函式的簽名對映到一個新的標識?我的第一反應是:函式名+引數列表,因為函式過載取決於引數的型別、個數,而跟返回型別無關。但看下面的對映關係:
void print(int i) --> _Z5printi
void print(string str) --> _Z5printSs
進一步猜想,前面的Z5表示返回值型別,print函式名,i表示整型int,Ss表示字串string,即對映為返回型別+函式名+引數列表。最後在main函式中就是通過_Z5printi、_Z5printSs來呼叫對應的函式的:
80489bc: e8 73 ff ff ff call 8048934 <_Z5printi>
……………
80489f0: e8 7a ff ff ff call 804896f <_Z5printSs>
我們再寫幾個過載函式來驗證一下猜想,如:
void print(long l) --> _Z5printl
void print(char str) --> _Z5printc
可以發現大概是int->i,long->l,char->c,string->Ss….基本上都是用首字母代表,現在我們來現在一個函式的返回值型別是否真的對函式變名有影響,如:
#include<iostream>
using namespace std;
int max(int a,int b)
{
return a>=b?a:b;
}
double max(double a,double b)
{
return a>=b?a:b;
}
int main()
{
cout<<"max int is: "<<max(1,3)<<endl;
cout<<"max double is: "<<max(1.2,1.3)<<endl;
return 0;
}
int max(int a,int b)
對映為_Z3maxii、double max(double a,double b)
對映為_Z3maxdd,這證實了我的猜想,Z後面的數字程式碼各種返回型別。更加詳細的對應關係,如那個數字對應那個返回型別,哪個字元代表哪重引數型別,就不去具體研究了,因為這個東西跟編譯器有關,上面的研究都是基於g++編譯器,如果用的是vs編譯器的話,對應關係跟這個肯定不一樣。但是規則是一樣的:“返回型別+函式名+引數列表”。然返回型別也考慮到對映機制中,這樣不同的返回型別對映之後的函式名肯定不一樣了,但為什麼不將函式返回型別考慮到函式過載中呢?——這是為了保持解析操作符或函式呼叫時,獨立於上下文(不依賴於上下文),看下面的例子
float sqrt(float);
double sqrt(double);
void f(double da, float fla)
{
float fl=sqrt(da);//呼叫sqrt(double)
double d=sqrt(da);//呼叫sqrt(double)
fl=sqrt(fla);//呼叫sqrt(float)
d=sqrt(fla);//呼叫sqrt(float)
}
如果返回型別考慮到函式過載中,這樣將不可能再獨立於上下文決定呼叫哪個函式。
5. 總結
從過載的機制來看,並不是沒法實現返回值型別不同情況下的函式過載,只是從獨立於上下文的出發點考慮,所以才沒有支援。
關於c++函式過載的更多介紹可以參考C++的函式過載。
相關推薦
C++中的函式過載中為什麼不考慮返回值型別?
1. 問題描述 函式過載是指在同一作用域內,可以有一組具有相同函式名,不同引數列表的函式,這組函式被稱為過載函式。那為什麼不可以是函式名相同,引數列表相同,函式的返回值不同呢? 2. 從一個函式過載例項說起 看下面的一個例子,來體會一下:實現一個列印
java方法的過載與覆蓋的返回值型別
首先看一段程式:package testOverLoadandoverRide;public class A extends B{//下面的是方法的覆蓋(overRiding)public void riding(){System.out.println("this is
究極難題 :一個執行10秒以上至無窮的呼叫函式,成功後有返回值。在多工執行緒中怎麼實現呼叫不卡住該執行緒?
究極難題 :一個執行10秒以上至無窮的呼叫函式,成功後有返回值。在多工執行緒中怎麼實現呼叫不卡住該執行緒? Note:一旦呼叫函式,中途無法取消。 思路一:讓其執行在獨立執行緒內。加超時時間。 1. 在超時時間內函式有返回值,則函式執行結束。則獨立執行緒結束。 2. 在超時時
<C++學習二十>C++中函式過載的理解(未完待續)
摘要: 本篇部落格僅作為筆記,如有侵權,請聯絡,立即刪除(網上找部落格學習,然後手記筆記,因紙質筆記不便儲存,所以儲存到網路筆記)。 我們平時寫程式碼中會用到幾個函式但是他們的實現功能相同,但是有些細節卻不同。例如:交換兩個數的其中包括(int,float,char,double)這些型別。這C語言中我
C語言函式傳遞中形參的變化不會改變實參的值
如題,C語言在函式間傳遞引數時,形參的變化是不會改變實參的值的!!! 如: include<stdio.h> void main(){ void swap(int,int); int a,b; scanf("%d,%d",&a,&b)
函式中有多個return?C語言中,一個函式可以有幾個返回值?
在移植wifi的程式碼時,遇到了一些與下面類似的函式,這些函式中有不只一個return,這可是個新鮮的玩意兒: int func (int b) { int a=5; if (a>b) return a; else
C++中函式過載、隱藏、覆蓋和重寫的區別 轉自:http://www.bijishequ.com/detail/277975?p=
程式碼編譯執行環境:VS2012+Debug+Win32 1.函式過載(Function Overload) 1.1定義 C++規定在同一作用域中,同名函式的形式引數(指引數的個數、型別或者順序)不同時,構成函式過載。 1.2用法 比如,要從兩個變數中返回其中較
C語言中函式的思考(可以返回區域性變數嗎)
一般的來說,函式是可以返回區域性變數的。 區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體已經釋放了。因此,如果函式返回的是區域性變數的值,不涉及地址,程式不會出錯。但是如果返回的是區域性變數的地址(指標)的話,程式執行後會出錯。因為函式只是把指標複製後返
C++:“函式模板“中對“非型別引數”作偏特化時遇到的問題
在使用 “函式模板“對“非型別引數”作偏特化時遇到編譯報錯的問題,程式碼及報錯資訊如下 template<typename T, int size> void toStr() { cout << "1.---------------------" <<
C++中的RVO優化,針對返回值為物件時臨時物件的優化
摘要: RVO (return value optimization) 和NRVO (named return value optimization) 是C++在處理一個函式返回類物件並將返回值賦給另一個物件時,為了減少拷貝構造次數以及析構次數而採用的一種編譯器優化技術。 當函式的返回值
mybaits中設定的返回值型別為boolean型別,當查詢的結果大於1時返回True而不是false
在Mybatis專案中,遇到一個需要返回布林值來確定某條記錄是否存在的需求。由於查詢的結果可能是0、1或者>1,就想確認一下,當resultType為boolean型別時,Mybatis是怎麼轉換的。查詢了一下部落格,一些部落格說:當記錄數行數是1時返回true,行數為
python中函式的返回值型別
import os import sys def AddSubMul(x=8,y=4): return ((x+y),(x-y),(x*y)) def AddSubMul2(x=8,y=4): return [(x+y),(x-y),(x*
【c++】cout過載能不能寫成成員函式,若能,寫出函式原型,若不能,說明原因
// cout過載能不能寫成成員函式,若能,寫出函式原型,若不能,說明原因 #include <iostream> using namespace std; // cout做友元 class A; ostream& operator<<(
C語言中函式呼叫中的傳值與傳址
首先介紹一下函式中傳值與傳址的概念: 傳值:傳值,實際是把實參的值賦值給行參,相當於copy。那麼對行參的修改,不會影響實參的值 。 傳址: 實際是傳值的一種特殊方式,只是他傳遞的是地址,不是普通的賦值,那麼傳地址以後,實參和行參都指向同一個物件,因此對形參
[轉]C#進階系列——WebApi 接口返回值不困惑:返回值類型詳解
try 接口測試工具 des rep home creat port 調用 學習 本文轉自:http://www.cnblogs.com/landeanfen/p/5501487.html 閱讀目錄 一、void無返回值 二、IHttpActionResult
(四)Asp.net web api中的坑-【api的返回值】
技術分享 要求 data 都是 blog pan odi handle 自己 void無返回值 IHttpActionResult HttpResponseMessage 自定義類型 我這裏並不想贅述這些返回類型, 可以參考博文http://blog.csdn.net/
struts2在配置文件中調用Action的方法返回值
ack 文件下載 返回 public class int cat chm webex struts2在配置文件中可以調用Action的方法返回值 1.Action中 //文件下載名 public String getDownloadFileName(){
C++小結--函式過載
1 什麼是函式過載 在C++中,一個函式名有多個函式體的實現方式就叫做函式過載。換句話說,我們使用同一個函式,傳入不同的引數,會返回不同的呼叫結果。 2 為什麼需要函式過載 函式過載可以提高函式呼叫的靈活性,我們不必再為函式名名而苦惱。比如在C語言中,我們要計算加法,可以寫如
C++學習--函式過載
C++支援函式的過載,函式的過載說的是在同一個程式出現多個同名的函式,實現的是同一類的功能。例如:求和,有時需要求整型的和、有時求浮點型的和,有時求和的個數不同。所以,函式的過載在這方面給程式提供了極大的便利。 函式過載需要引數個數、引數型別或者引數順序三者至少要有一種不同。因為系統是根據引數找
MyBatis中Mapper的返回值型別
insert、update、delete語句的返回值型別 對資料庫執行修改操作時,資料庫會返回受影響的行數。 在MyBatis(使用版本3.4.6,早期版本不支援)中insert、update、delete語句的返回值可以是Integer、Long和Boolean。在定義Mapper介面時直接指定需要的型