C++中同名函數之間的關係

在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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章