在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()