1. 程式人生 > >C++中的函式過載中為什麼不考慮返回值型別?

C++中的函式過載中為什麼不考慮返回值型別?

1. 問題描述

函式過載是指在同一作用域內,可以有一組具有相同函式名不同引數列表的函式,這組函式被稱為過載函式。那為什麼不可以是函式名相同,引數列表相同,函式的返回值不同呢?

2. 從一個函式過載例項說起

          看下面的一個例子,來體會一下:實現一個列印函式,既可以列印int型、也可以列印字串型。在C++中,我們可以這樣做:

#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;
}
          通過上面程式碼的實現,可以根據具體的print()的引數去呼叫print(int)還是print(string)。上面print(12)會去呼叫print(int),print("hello world")會去呼叫print(string)

3. 為什麼需要函式過載(why)?

  • 試想如果沒有函式過載機制,如在C中,你必須要這樣去做:為這個print函式取不同的名字,如print_int、print_string。這裡還只是兩個的情況,如果是很多個的話,就需要為實現同一個功能的函式取很多個名字,如加入列印long型、char*、各種型別的陣列等等。這樣做很不友好!
  • 類的建構函式跟類名相同,也就是說:建構函式都同名。如果沒有函式過載機制,要想例項化不同的物件,那是相當的麻煩!
  • 操作符過載,本質上就是函式過載,它大大豐富了已有操作符的含義,方便使用,如+可用於連線字串等!

通過上面的介紹我們對函式過載,應該喚醒了我們對函式過載的大概記憶。下面我們就來分析,C++是如何實現函式過載機制的

4. 函式過載為什麼不考慮返回值型別

         為了弄清楚這個問題,我們先看看宣告/定義過載函式時,是如何解決命名衝突的?

        為了瞭解編譯器是如何處理這些過載函式的,我們反編譯下上面我們生成的執行檔案,看下彙編程式碼(全文都是在Linux下面做的實驗,Windows類似,你也可以參考《一道簡單的題目引發的思考》一文,那裡既用到Linux下面的反彙編和Windows下面的反彙編,並註明了Linux和Windows組合語言的區別)。我們執行命令objdump -d a.out >log.txt

反彙編並將結果重定向到log.txt檔案中,然後分析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) 對映為_Z3maxiidouble 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++支援函式的過載,函式的過載說的是在同一個程式出現多個同名的函式,實現的是同一類的功能。例如:求和,有時需要求整型的和、有時求浮點型的和,有時求和的個數不同。所以,函式的過載在這方面給程式提供了極大的便利。 函式過載需要引數個數、引數型別或者引數順序三者至少要有一種不同。因為系統是根據引數找

MyBatisMapper的返回型別

insert、update、delete語句的返回值型別 對資料庫執行修改操作時,資料庫會返回受影響的行數。 在MyBatis(使用版本3.4.6,早期版本不支援)中insert、update、delete語句的返回值可以是Integer、Long和Boolean。在定義Mapper介面時直接指定需要的型