私はc ++で仮想キーワードと継承の概念をテストしています。私は小さなプログラムを書きました:
#include<stdio.h>
#include<iostream>
using namespace std;
class cna_MO
{
public:
virtual void print()
{
cout << "cna_MO" << endl;
}
};
class cna_bsc:public cna_MO
{
public:
void print()
{
cna_MO::print();
}
void print(int a)
{
cout << "cna_BSC" << endl;
}
};
class cna_Mo
{
cna_MO *_mo;
public:
cna_Mo()
{
_mo = new cna_bsc;
}
virtual void print(int a)
{
cout << "cna_Mo with arg" << endl;
_mo->print(5);
}
virtual void print()
{
cout << "cna_Mo" << endl;
_mo->print();
}
};
int main()
{
cna_Mo valid_mo;
cout << "old case is started" << endl;
valid_mo.print();
cout << "new case is started" << endl;
valid_mo.print(5);
return 0;
}
ここで行ったことは、子クラスの親クラスの仮想関数をオーバーロードしたことです。これは正しいことではありませんか?
以下のようなコンパイルエラーが発生します:
「temp10.cc」、45行目:エラー:「cna_MO :: print()」の呼び出しで引数が多すぎます。
DerivedクラスのBaseクラスから関数をオーバーロードすると、Baseクラスの同じ名前のすべての関数がDerivedクラスに非表示になります。
関数cna_bsc::print(int a)
を派生クラスに追加すると、関数cna_MO::::print()
はDerivedクラスのユーザーには表示されなくなります。これは、関数の非表示として知られています。
解決策:非表示の関数を派生クラスで表示するには、次を追加する必要があります。
using cna_MO::print;
派生クラスのpublic
セクション内cna_bsc
。
良い読み物:
理想的には、intをとるプリントの名前は異なるはずですが、両方の関数をprintと呼びたい場合は、両方を非仮想にし、保護された仮想関数を呼び出すようにする必要があります。
class cna_MO
{
public:
void print() { doPrint(); }
protected:
virtual void doPrint()
{ cout << "cna_MO" << endl;
}
};
class cna_bsc:public cna_MO
{
protected:
virtual void doPrint()
// although with implementation no need to override it
{
cna_MO::print();
}
public:
void print(int a)
{
doPrintInt( a );
}
protected:
virtual void doPrintInt( int )
{
cout << "cna_BSC" << endl;
}
};
本当にこのようにする必要がある場合、つまり、1つのクラスへのポインターを持ち、派生クラスとして初期化する場合、それを使用するときは常に正しい型にポインターをキャストする以外に選択肢はありません。この場合、 ((cna_bsc*)_mo)->print(5);
派生クラスに基本クラスと同じ名前で異なるパラメーターを持つ関数がある場合、その関数はhiddenになります。あなたはより多くの情報を見つけることができます ここ ..
Base::hiddenFun();
のように呼び出すことで、特定の隠し関数を呼び出すことができます。
_cna_MO *
_が与えられた場合、コンパイル時に、ポイントされたオブジェクトに(必然的に)intオーバーロードがないことがわかります。実際に基本クラスのオブジェクトを指している場合、_mo->print(5);
は実際には何も呼び出す必要がありません。また、この呼び出しをサポートする必要のない(まだ実装されていない)派生クラスが無数に存在する可能性があります。
すべての派生クラスにはprint(int)
が必要です-基本クラスで宣言します。
すべての派生クラスにprint(int)
を含める必要はありません--_cna_Mo
_は_cna_bsc
_でのみ機能するため、メンバーは_cna_bsc* _mo
_である必要があります。
これは、子クラスのprint関数がパラメーターを受け取り、元の関数がパラメーターを受け取らないためです。
cna_MO(親クラス)内:
virtual void print()
cna_bsc(子クラス)内:
void print(int a)
基本的に、子供のプリントはint引数を取るべきではありません:
void print()
編集:
たぶん、intの受け渡しをオプションにするのが最善でしょう?
例えば:
cna_MO(親クラス)内:
virtual void print(int a=-1) {
if (a == -1) {
// Do something for default param
} else {
cout << a;
}
}
cna_bsc(子クラス)内:
void print(int a=-1)
したがって、おそらくa == -1の場合、何も渡されませんでした。
秘訣は、親と子の両方が同じメソッドsigantureを必要とすることです。つまり、同じ戻り値の型と同じ引数の型を意味します。