一、函數重載
1、問題的引入
在實際開發中,有時候我們需要實現幾個功能類似的函數,只是有些細節不同。例如希望交換兩個變量的值,這兩個變量有多種類型,可以是 int、float、char、bool 等,我們需要通過參數把變量的地址傳入函數內部。在C語言中,程序員往往需要分別設計出三個不同名的函數,其函數原型與下面類似:
void swap1(int *a, int *b); //交換 int 變量的值
void swap2(float *a, float *b); //交換 float 變量的值
void swap3(char *a, char *b); //交換 char 變量的值
void swap4(bool *a, bool *b); //交換 bool 變量的值
那么在C++中,有沒有一種方法,允許多個函數擁有相同的名字,只要它們的參數列表不同就可以呢。
答案:使用函數重載。
2、概念
用相同的函數名定義多個不同的功能稱為函數重載。重載的函數根據參數的個數和類型進行區分,但不能單獨根據返回類型進行區分。
3、例子
void swap(int *a,int *b)
{*a = *a + *b;*b = *a - *b;*a = *a - *b;
}
void swap(float *a,float *b)
{*a = *a + *b;*b = *a - *b;*a = *a - *b;
}
void swap(char *a,char *b)
{*a = *a + *b;*b = *a - *b;*a = *a - *b;
}
void swap(bool *a,bool *b)
{*a = *a + *b;*b = *a - *b;*a = *a - *b;
}
在函數調用的時候會根據不同的參數列表選擇調用對應的函數
4、函數重載的規則
- 函數名稱必須相同
- 參數列表必須不同(個數不同、類型不同、參數排列順序不同等)
- 函數的返回類型可以相同也可以不相同。
- 僅僅返回類型不同不足以成為函數的重載
5、函數重載的作用 - 解決函數名字資源問題
- 函數調用的時候很方便,自動根據不同的參數調用不同函數(靜態多態-編譯時候多態)
6、注意
在c++中編譯器會檢查函數名稱和參數列表, 在c語言中編譯器只檢查函數名稱
7、函數重載原理
總結:返回值不一樣不能實現函數重載
const參數能實現函數重載
二、函數默認參數(缺省實參)和占位參數
1、概念
在聲明函數的時候可以賦予函數參數默認值。所謂默認值就是在調用時,可以不寫某些參數的值,編譯器會自動把默認值傳遞給調用語句中。
2、特點
- 如果函數的聲明和定義是分開的,必須在聲明的時候設置默認值,不可以在定義的時候設置默認值;
- 不能將實際值傳遞給引用類型的參數。可以將變量作引用類型參數的默認值,這時變量必須是已經聲明且是全局變量
#include<iostream>using namespace std;int g_val = 10;//默認值是在函數聲明的時候進行設置
int func(int a=10);
//不能將實際值傳遞給引用類型的參數。可以將變量作引用類型參數的默認值,這時變量必須是已經聲明且是全局變量
//int rfunc(int &a=10); --除非 const int &a=10
int rfunc(int &a=g_val);int main()
{func();return 0;
}
//如果函數的定義和聲明是分開的,那么函數定義的時候不能設置默認值,而是在聲明的時候進行設置
int func(int a)
{cout<<"a:"<<a<<endl;
}
int rfunc(int &a)
{cout<<"a:"<<a<<endl;
}
- 若給某一參數設置了默認值,那么在參數表中其后所有的參數都必須也設置默認值
如果多參數默認,必須滿足從右往左連續默認
void fun(int a, int b=9, int c=1); 允許
void fun(int a=1, int b, int c=2); 不允許
3、占位參數
占位參數:跟默認參數不同,在函數定義時,形參只寫類型,不寫形參變量名
語法:
返回值類型 函數名(type ) //type --- int char
{}
占位參數的使用場景比較少,只在運算符重載中可以應用
void test(int) //占位參數
{}
void test1(char) //占位參數
{}
int main()
{int b = 10;test(b); //帶占位參數的函數調用時,要傳入對應類型的參數值return
}
練習5:使用鏈表設計一個錄入學生信息的函數(參數為學生信息)(輸入信息有個學號,姓名,年齡,班級 參數順序自定),結合函數重載和默認參數的特點,設計的時候使后期使用更方便
#include <iostream>
#include <cstring>/* 練習2:設計一個錄入學生信息的函數(參數就是學生信息)
(輸入的時候有姓名、年齡、班級...),結合函數重載和默認參數的特點
設計出來的程序使用的時候 更加方便 */using namespace std;enum MODE
{ADD, //增加SHOW, //顯示EXIT //退出
};struct student{char name[256];int age;char classes[256];//班級
};//單向非循環鏈表
typedef struct node{struct student info;//數據域struct node *next;//指針域
}Node_t;//鏈表的頭結點
typedef struct list{Node_t *head;//數據的首結點Node_t *tail;//數據的尾結點int nodeNumber;//鏈表中結點的個數
}List_t;List_t *create_list()
{//1、申請一個頭結點的內存空間List_t *list = new List_t;list->head = list->tail = NULL;list->nodeNumber = 0;return list;
}void insert_nodeToList_tail(List_t *list,const char *name,const int age=21,const char *classes="gz2166")
{if(list==NULL)return ;//1、新建數據結點Node_t *newNode = new Node_t;//2、初始化strcpy(newNode->info.name,name);newNode->info.age = age;strcpy(newNode->info.classes,classes);newNode->next = NULL;//3、將新建的結點插入到鏈表中if(list->head == NULL) //從無到有{list->head = newNode;list->tail = newNode;}else{ //從少到多 ---尾插法//當前尾結點的next指向新結點list->tail->next = newNode;//更新尾結點list->tail = newNode;}list->nodeNumber++;}void print_allToList(List_t *list)
{Node_t *p = list->head;cout<<"姓名\t\t"<<"年齡\t"<<"班級\t"<<endl;while(p){cout<<p->info.name<<"\t\t"<<p->info.age<<"\t"<<p->info.classes<<"\t\t"<<endl;p = p->next;}
}int main()
{List_t *list = create_list();insert_nodeToList_tail(list,"zhang3",22);insert_nodeToList_tail(list,"li4");insert_nodeToList_tail(list,"laowang",23,"gz2169");print_allToList(list);return 0;
}
四、函數重載與函數默認參數
思考:假如一個程序中有如下兩個函數
void test()
{
}
void test(int x=10)
{
}
調用:
test(11);//調用 的是:void test(int x=10)
test();//調用的是???歧義
答案:有歧義,解決方法:可以定義命名空間