web-dev-qa-db-ja.com

子クラスの仮想関数のオーバーロード

私は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()」の呼び出しで引数が多すぎます。

14
Vijay

DerivedクラスのBaseクラスから関数をオーバーロードすると、Baseクラスの同じ名前のすべての関数がDerivedクラスに非表示になります。

関数cna_bsc::print(int a)を派生クラスに追加すると、関数cna_MO::::print()はDerivedクラスのユーザーには表示されなくなります。これは、関数の非表示として知られています。

解決策:非表示の関数を派生クラスで表示するには、次を追加する必要があります。

using cna_MO::print;

派生クラスのpublicセクション内cna_bsc

良い読み物:

警告:派生:: f(char)はBase :: f(double)を非表示にしますか?

23
Alok Save

理想的には、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;     
      } 
 };  
0
CashCow

本当にこのようにする必要がある場合、つまり、1つのクラスへのポインターを持ち、派生クラスとして初期化する場合、それを使用するときは常に正しい型にポインターをキャストする以外に選択肢はありません。この場合、 ((cna_bsc*)_mo)->print(5);

0
Mr Lister

派生クラスに基本クラスと同じ名前で異なるパラメーターを持つ関数がある場合、その関数はhiddenになります。あなたはより多くの情報を見つけることができます ここ ..

Base::hiddenFun();のように呼び出すことで、特定の隠し関数を呼び出すことができます。

0
liaK

_cna_MO *_が与えられた場合、コンパイル時に、ポイントされたオブジェクトに(必然的に)intオーバーロードがないことがわかります。実際に基本クラスのオブジェクトを指している場合、_mo->print(5);は実際には何も呼び出す必要がありません。また、この呼び出しをサポートする必要のない(まだ実装されていない)派生クラスが無数に存在する可能性があります。

  1. すべての派生クラスにはprint(int)が必要です-基本クラスで宣言します。

  2. すべての派生クラスにprint(int)を含める必要はありません--_cna_Mo_は_cna_bsc_でのみ機能するため、メンバーは_cna_bsc* _mo_である必要があります。

0
visitor

これは、子クラスの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を必要とすることです。つまり、同じ戻り値の型と同じ引数の型を意味します。

0
matiu