C++中繼承覆寫導致基類的成員不可見

在C++中,基類定義了一個成員函數 f(),派生類定義了一個成員函數 f(int),然後派生類來調用:pDerieved->f(),結果會怎樣?

派生類的重載定義,會導致基類的函數在名稱查找的時候,不可見。但是C++的設計哲學,又可以讓你用using聲明實現基類成員函數在派生類中重載。



代碼一:

#include<iostream>
#include<string>

using namespace std;

class Base
{
	public:
		void f()
		{
			cout<<"f()"<<endl;
		}
};

class Derive:public Base
{
	public:
		void f(int i)
		{
			cout<<"f(int) i="<<i<<endl;
		}

};


int main()
{
	Derive x;
        x.f(1);  //OK
        x.f();   //錯誤,參數格式錯誤。無參數的 f() 不可見
        return 0;
}


關於基類f()的隱藏,其實是因爲類的作用域導致的,在C++中,派生類的作用域是嵌套在基類當中的。

 編譯器對類的成員進行名稱查找的時候,編譯器先在派生類當中查找,如果沒找到,再到基類中查找,如果還沒有找到,在到基類的基類中查找,一直查找到繼承的最頂端。如果在繼承的頂端還是沒有找到,則報錯。


本例中查找,x.f,編譯器通過x的靜態類型:Derive,在其作用域當中查找f(),

很幸運,編譯器馬上就找到了f(int),雖然函數簽名不一樣,但是函數名稱一樣,編譯就不會繼續往下查找了。但是f(int) 需要一個 int類型的參數,我們調用的參數少了,於是編譯器報錯。


代碼二:

#include<iostream>
#include<string>

using namespace std;

class Base
{
	public:
		void f()
		{
			cout<<"f()"<<endl;
		}
};

class Derive:public Base
{
	public:
		using Base::f;  //聲明基類的作用域
		void f(int i)
		{
			cout<<"f(int) i="<<i<<endl;
		}

};


int main()
{
	Derive x;
	x.f();   //ok
  return 0;
}

通過在派生類中聲明基類的函數名稱,在派生類中也能找到基類的函數了


執行結果:

AlexdeMacBook-Pro:~ alex$ a.out
f()


代碼三:


#include<iostream>
#include<string>

using namespace std;

class Base
{
	public:
		void f()
		{
			cout<<"f()"<<endl;
		}
};

class Derive:public Base
{
	public:
		void f(int i)
		{
			cout<<"f(int) i="<<i<<endl;
		}

};


int main()
{
	Derive x;
	Base *p=&x;
	p->f();   //OK
        
        return 0;
}

編譯器通過p的靜態類型Base,找到了f(),於是調用了基類的f()


代碼四:

#include<iostream>
#include<string>

using namespace std;

class Base
{
	public:
		void f()
		{
			cout<<"f()"<<endl;
		}
};

class Derive:public Base
{
	public:
		void f(int i)
		{
			cout<<"f(int) i="<<i<<endl;
		}
		
		void f()
		{
			cout<<"Derive f()"<<endl;
		}

};


int main()
{
	Derive x;
	Base *p=&x;
	p->f();   //OK
	x.f();     //OK
  return 0;
}

執行結果:

AlexdeMacBook-Pro:~ alex$ a.out
f()
Derive f()


發佈了18 篇原創文章 · 獲贊 25 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章