在C++中同名函數有三種關係:
- 重載(overlode):相同作用域;函數名相同;參數列表不同(參數類型不同,或者參數個數不同,或者參數個數和參數類型都不相同);返回類型隨意。
- 覆蓋(override):不同作用域下(分別在父類和子類中);函數名相同;參數列表列表相同;返回類型相同(協變除外);基類函數必須有virtual修飾;父類和子類的訪問限定可以不同。
- 隱藏(overhide):不同作用域下(分別在父類和子類中);函數名相同;除過覆蓋的同名函數都是隱藏關係。
一:重載
產生原因:主要是因爲在C++中,編譯器在編譯.cpp文件中當前作用域的同名函數時,函數生成的符號由返回值類型(不起決定作用)+形參類型和順序(起決定作用)的組成。
作用:用同一個函數名命名一組功能相似的函數,這樣做減少了函數名的數量,避免了名字空間的污染,對於程序的可讀性有很大的好處。
int sum(int a,int b)
{
return a+b;
}
double sum(double a,double b)
{
return a+b;
}
float sum(float a,float b)
{
return a+b;
}
int main()
{
/*
調用函數名相同的函數,
根據實參的類型和實參的順序以及實參的個數選擇相應的函數
*/
int a=sum(10,20);//調用的是int sum(int a,int b)
//call sum (010B1447h) ==》 靜態的綁定
float b=sum(2.5f,3.2f);//調用的是float sum(float a,float b);
//call sum (010B145Bh) ==》 動態的綁定
cout<<a<<endl;
cout<<b<<endl;
return 0;
}
同樣的如下也構成重載
void add(int* a)//參數類型不同
{
cout<<*a<<endl;
}
void add(int& a)
{
cout<<a<<endl;
}
int main()
{
int a=10;
add(&a);
add(a);
}
二、覆蓋
在子類中定義了一個與父類完全相同的函數時,稱子類這個函數覆蓋了父類的這個虛函數。完全相同代表着兩個函數的函數名、參數個數、參數類型、返回值類型都相同;也有特殊例子(協變)。
覆蓋的作用:實現動態的多態。
第一種情況:
//情況一:普通情況
class Base
{
public:
virtual void Show()
{
cout<<"Base::Show()"<<endl;
}
protected:
int ma;
};
class Derive:public Base
{
public:
/*在子類中定義了一個和父類虛函數完全相同的函數;
如果不顯示加上virtulal修飾,編譯器會默認爲虛函數。
*/
void Show()
{
cout<<"Derive::Show()"<<endl;
}
protected:
int mb;
};
void Fun(Base* p)
{
p->Show();
}
void Fun(Base& p)
{
p.Show();
}
int main()
{
Base p;
Derive d;
Fun(p);
Fun(&p);
/*
打印的是Derive::Show()
父類的引用引用了基類的對象,調用覆蓋函數時調用的是基類的虛函數
*/
Fun(d);
/*
打印的是Derive::Show()
父類的指針指向了基類的對象,調用覆蓋函數時調用的是基類的虛函數
*/
Fun(&d);//打印的是Derive::Show()
return 0;
}
第二種情況:
協變:子類的虛函數和父類中的虛函數的函數名、參數個數、參數類型都相同,只是返回值類型不同,父類的虛函數返回的時父類的指針或者引用,子類的虛函數返回的時子類的指針或者引用,這種情況下也會產生子類的虛函數覆蓋父類的虛函數。
//情況二:協變覆蓋
class Base
{
public:
virtual Base& Show()//基類的虛函數返回基類的引用
{
cout<<"Base::Show()"<<endl;
return *this;
}
protected:
int ma;
};
class Derive:public Base
{
public:
Base& Show()//子類的虛函數,返回子類的引用
{
cout<<"Derive::Show()"<<endl;
return * this;
}
protected:
int mb;
};
void Fun(Base* p)
{
p->Show();
}
void Fun(Base& p)
{
p.Show();
}
int main()
{
Base p;
Derive d;
Fun(p);
Fun(&p);
Fun(d);//call eax
Fun(&d);
return 0;
}
三、隱藏:
隱藏的不光是成員函數,還可以是成員變量。
★在子類的內部或者外部(通過子類成員)訪問該成員,全部訪問的子類同名成員。
★在子類的內部或者外部(通過子類成員)訪問該同名的成員函數,調用的是子類的成員函數。
class A
{
public:
A(int x=10):ma(x),mb(x){}
//舉例1
//void Show()
//{
// cout<<"A::Show()"<<endl;
//}
//舉例2
//virtual void Show()
//{
// cout<<"A::Show()"<<endl;
//}
//舉例2
void Show(int a)
{
cout<<"A::Show(int)"<<endl;
}
public:
int ma;
int mb;
};
class B:public A
{
public:
B(int x=20):ma(x){}
//舉例1
//void Show()
//{
// cout<<"B::Show()"<<endl;
// cout<<ma<<endl;//在子類中訪問同名的成員,訪問的是子類中的
//}
//舉例2
//void Show(int a)
//{
// cout<<"B::Show()"<<endl;
// cout<<ma<<endl;
//}
//舉例3
void Show(int a,int b)
{
cout<<"B::Show()"<<endl;
cout<<ma<<endl;
}
public:
int ma;
};
/*
A::
B::
ma
mb
ma
*/
int main()
{
B b;
cout<<(b.ma)<<endl;
cout<<(b.mb)<<endl;
//b.show(1);
b.Show(1,2);
return 0;
}