クラス A で f と名付けられたメンバー関数は、
戻りの型や引き数に関係なく、A の基底クラスで、他の f という名前のメンバーをすべて隠します。
次の例は、このことを示しています。
struct A { void f() { } }; struct B : A { void f(int) { } }; int main() { B obj_B; obj_B.f(3); // obj_B.f(); }
コンパイラーは、void B::f(int) の宣言が A::f() を隠しているので、 関数呼び出し obj_B.f() を許可しません。
基底クラス A の関数を、派生クラス B で、 隠蔽ではなく多重定義するには、using 宣言を使用して、 関数の名前を B のスコープに導入します。 以下の例は、using 宣言 using A::f を除いては、直前の例と同じです。
struct A { void f() { } }; struct B : A { using A::f; void f(int) { } }; int main() { B obj_B; obj_B.f(3); obj_B.f(); }
クラス B に using 宣言があるので、 名前 f は 2 つの関数で多重定義されます。 これで、コンパイラーは、関数呼び出し obj_B.f() を許可します。
同じ方法で仮想関数を多重定義できます。 次の例は、このことを示しています。
#include <iostream> using namespace std; struct A { virtual void f() { cout << "void A::f()" << endl; } virtual void f(int) { cout << "void A::f(int)" << endl; } }; struct B : A { using A::f; void f(int) { cout << "void B::f(int)" << endl; } }; int main() { B obj_B; B* pb = &obj_B; pb->f(3); pb->f(); }
次に、上記の例の出力を示します。
void B::f(int) void A::f()
関数 f を、using 宣言を指定して、基底クラス A から派生クラス B に導入し、さらに A::f として同じパラメーター型を持つ B::f という名前の関数が存在するとします。 関数 B::f は、関数 A::f と競合するというより、むしろそれを隠蔽します。 次の例は、このことを示しています。
#include <iostream> using namespace std; struct A { void f() { } void f(int) { cout << "void A::f(int)" << endl; } }; struct B : A { using A::f; void f(int) { cout << "void B::f(int)" << endl; } }; int main() { B obj_B; obj_B.f(3); }
次に、上記の例の出力を示します。
void B::f(int)
関連参照