C++ Call Base Class メソッド
このチュートリアルでは、C++ を使用して子クラスから親クラスのメソッドを呼び出す方法について説明します。 まず、継承をすばやく更新します。
後で、さまざまなシナリオでの基底クラス メソッドの呼び出しと関連する問題について説明します。
C++ での継承
継承は、オブジェクト指向プログラミングの強力な機能です。 継承により、子クラスは親クラスの属性と関数を共有できるため、OOP での再利用が容易になります。
継承では、2つのクラスが親子関係、ベース派生関係、または一般化特殊化関係として知られる関係になります。 ただし、親と子の代わりに基本派生の専門用語が最も一般的に採用されています。
C++ での継承の構文:
class Parent {
..
};
class Child : InheritanceSpecifier Parent {
...
};
派生クラスを作成するには、InheritanceSpecifier
の後に基本クラスの名前を付ける必要があります。 ここで、InheritanceSpecifier
は public
、private
、または protected
にすることができます。
また、継承時に複数の親クラスの名前を指定した場合、継承は 複数
になる可能性があります。 継承の種類の詳細については、こちら を参照してください。
物事を単純にするために、この記事全体で public
継承を使用します。 以下のコードに示すように、子クラス内および子クラスのオブジェクトを使用して、基本クラスのメソッド (private
でない場合) を呼び出すことができます。
class P {
public:
void pf() { cout << "Parent class function\n"; }
};
class C : public P {
public:
void cf() {
pf();
cout << "Child class function\n";
}
};
int main() {
C cObj;
cObj.cf();
cObj.pf();
return 0;
}
子クラス C
からパブリックに継承される親クラス P
を作成しました。 子クラス C
の cf()
関数は、基本メソッド pf()
を呼び出します。
同様に、ドライバー コード (つまり、main()
) では、子オブジェクト cObj
が基本クラス メソッドを直接呼び出します。
出力:
Parent class function
Child class function
Parent class function
上記の例は、基本クラス関数の呼び出しを理解するのに非常に簡単でした: 子クラス内および子クラスのオブジェクトを使用します。
ただし、次の節で説明するように、より複雑な状況では、基本メソッドを呼び出すときに追加の注意が必要になる場合があります。
基本クラス メソッドの呼び出しに関する問題
前のコードと出力では、基本クラス メソッドの呼び出しに問題はないようです。 ただし、親クラスと子クラスが同じ機能を持っている場合や、子に同じ機能を持つ親が 2つ以上ある場合など、いくつかの関連する問題が発生します。
これらの問題を 1つずつ説明しましょう。
親と子は同じ機能を持つ
親クラスと子クラスは同じ関数を持つ場合があり、場合によっては子クラス オブジェクトで親クラスの関数を呼び出したい場合や、子クラス内で親クラスの関数を呼び出したい場合があります。
まず、シナリオを示すコードを見てみましょう。
class Parent {
public:
void f() { cout << "Parent class function\n"; }
};
class Child : public Parent {
public:
void f() { cout << "Child class function\n"; }
};
int main() {
Child cObj;
cObj.f();
return 0;
}
出力:
Child class function
ここで、子クラス オブジェクトが (親からではなく) 子クラスの f()
関数を呼び出すことに注意してください。 子クラス オブジェクトを介して親の f()
を呼び出すには、次のコードに示すように、親クラス名とスコープ解決演算子 (::
) を使用する必要があります。
class Parent {
public:
void f() { cout << "Parent class function\n"; }
};
class Child : public Parent {
public:
void f() { cout << "Child class function\n"; }
};
int main() {
Child cObj;
cObj.Parent::f(); // calling f() of parent class
cObj.f();
return 0;
}
出力:
Parent class function
Child class function
スコープ解決演算子で親クラス名を使用した main()
関数の 2 行目を参照してください。 それに対応して、出力の最初の行で、親クラスの f()
によって出力されたメッセージを見ることができます。
以下のコードに示すように、子クラス内で基本クラス関数を呼び出すには、正確な構文に従う必要があります。
class Parent {
public:
void f() { cout << "Parent class function\n"; }
};
class Child : public Parent {
public:
void f() {
Parent::f();
cout << "Child class function\n";
}
};
int main() {
Child cObj;
cObj.f();
return 0;
}
出力:
Parent class function
Child class function
多重継承のあいまいさ
基本クラス メソッドの呼び出しに関する 2つ目の問題は、複数 (2つ以上) のクラスの親が同じメソッドを持つことができることです。 この場合、同じメソッドが複数の基本クラスに存在するため、コンパイラは特定の基本クラスを選択してメソッドを呼び出すのを混乱させます。
基本メソッドを呼び出すために特定の基本クラスを選択する際に、コンパイラのコンパイル時のあいまいさを生成するコードを見てみましょう。
class P1 {
public:
void fun() { cout << "Fun from P1\n"; }
};
class P2 {
public:
void fun() { cout << "Fun from P2\n"; }
};
class C : public P1, public P2 {};
int main() {
C objC;
objC.fun();
return 0;
}
ここで、クラス C
は 2つの基底クラス (つまり、P1
と P2
) から継承され、両方の親は同じシグネチャを持つ fun()
メソッドを持っています。
ここで、ドライバー コードが子オブジェクト (objC
) によって fun()
関数を呼び出すと、適切な基本クラスを選択する際にコンパイラが混乱します。
コンパイラ メッセージを調べてみましょう。
base_class_3.cpp: In function ‘int main()’:
base_class_3.cpp:16:7: error: request for member ‘fun’ is ambiguous
objC.fun();
このメッセージは、コンパイラが混乱していることを明確に示しています。 繰り返しますが、解決策はスコープ解決演算子でクラス名を使用することと同じです。
コードと関連する出力を参照してください。
class P1 {
public:
void fun() { cout << "Fun from P1\n"; }
};
class P2 {
public:
void fun() { cout << "Fun from P2\n"; }
};
class C : public P1, public P2 {};
int main() {
C objC;
objC.P1::fun();
objC.P2::fun();
return 0;
}
出力:
Fun from P1
Fun from P2
main()
の 2 行目と 3 行目を参照してください。ここでは、P1
と P2
クラス名がスコープ解決演算子で使用されています。 したがって、出力では、両方の基本関数からの出力を確認できます。