C++でのリロード、書き換え(上書き)と非表示の違い

7816 ワード

基本概念:リロード:同じアクセス可能な領域で宣言されたいくつかの異なるパラメータ列(パラメータのタイプ、個数、順序が異なる)を持つ同名の関数を指し、パラメータリストに基づいてどの関数を呼び出すかを決定し、リロードは関数の戻りタイプに関心を持たない.
例:
class A{
public:
  void test(int i);
  void test(double i);//overload
  void test(int i, double j);//overload
  void test(double i, int j);//overload
  int test(int i);         //  ,   。             。
};

≪非表示|Hide|emdw≫:生クラスを割り当てる関数は、同じ名前のベースクラス関数をマスクします.同じ名前の関数であれば、パラメータ・リストが同じかどうかにかかわらず、ベースクラス関数は非表示になります.
例:
#include 
using namespace std;

class Base
{
public:
    void fun(double ,int ){ cout << "Base::fun(double ,int )" << endl; }
};

class Derive : public Base
{
public:
    void fun(int ){ cout << "Derive::fun(int )" << endl; }
};

int main()
{
    Derive pd;
    pd.fun(1);//Derive::fun(int )
    pb.fun(0.01, 1);//error C2660: “Derive::fun”:       2    

    system("pause");
    return 0;
}

書き換え(上書き):生クラスに再定義が存在する関数を割り当てます.その関数名、パラメータリスト、戻り値タイプは、ベースクラスで書き換えられたすべての関数と一致する必要があります.関数体のみが異なる(カッコ内)場合、派生クラス呼び出し時に派生クラスの書き換え関数が呼び出され、書き換え関数は呼び出されません.書き換えられたベースクラスで書き換えられた関数にはvirtual修飾が必要です.
例:
#include

using namespace std;

class Base
{
public:
    virtual void fun(int i){ cout << "Base::fun(int) : " << i << endl;}
};

class Derived : public Base
{
public:
    virtual void fun(int i){ cout << "Derived::fun(int) : " << i << endl;}
};
int main()
{
    Base b;
    Base * pb = new Derived();
    pb->fun(3);//Derived::fun(int)

    system("pause");
    return 0;
}

リロードと書き換えの違い:
(1)範囲の違い:書き換えられた関数と書き換えられた関数は異なるクラスで,リロードされた関数とリロードされた関数は同じクラスである.
(2)パラメータの違い:書き換えは書き換えられた関数パラメータリストと必ず同じであり,リロードとリロードされた関数パラメータリストは必ず異なる.
(3)virtualの違い:書き換えのベースクラスにはvirtual修飾が必要であり,リロード関数とリロード関数はvirtual修飾してもよいし,なくてもよい.
非表示と書き換え、リロードの違い:
(1)リロード範囲とは異なる:非表示関数と非表示関数は異なるクラスにある.
(2)パラメータの違い:非表示関数と非表示関数のパラメータリストは同じでも異なってもよいが、関数名は必ず同じである;パラメータが異なる場合、ベースクラスの関数がvirtualによって修飾されるかどうかにかかわらず、ベースクラスの関数は書き換えられるのではなく非表示である.例
#include 

using namespace std;

class Base
{
public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    void g(float x){ cout << "Base::g(float) " << x << endl; }
    void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base
{
public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
    void g(int x){ cout << "Derived::g(int) " << x << endl; }
    void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

int main(void)
{
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
    // Good : behavior depends solely on type of the object
    pb->f(3.14f); //Derived::f(float) 3.14
    pd->f(3.14f); //Derived::f(float) 3.14

    // Bad : behavior depends on type of the pointer
    pb->g(3.14f); //Base::g(float) 3.14
    pd->g(3.14f); //Derived::g(int) 3

    // Bad : behavior depends on type of the pointer
    pb->h(3.14f); //Base::h(float) 3.14
    pd->h(3.14f); //Derived::h(float) 3.14

    system("pause");
    return 0;
}

(1)関数Derived::f(float)はBase::f(float)を上書きする.
(2)関数Derived::g(int)は,リロードではなくBase::g(float)を非表示にする.
(3)関数Derived::h(float)はBase::h(float)を非表示にし,上書きではない.