C++親と子の関係、および関数の再ロード、上書き、非表示の規則


今日HTC面接に行って、笔记试験はロジック、c言语、c++言语のいくつかの部分を试験して、C/C++试験のはすべて基本的な文法で、アルゴリズムを试験していません.C言語の部分は悪くないが、C++の部分はそんなに不確定で、その大部分はC++親子クラス間の関係と関数の再ロード、上書き、隠蔽規則である.C++言語では,虚関数は非常に重要な概念であり,虚関数はC++のオブジェクト向けにおける多態性と継承性を実現する礎である.多態性と継承性はオブジェクト向け言語の真髄である.虚関数を身につけることこそ本当にC++言語を身につけることであり、C++言語の虚関数の継承カバーは関数の再ロードと似ており、多くの初心者は彼らの関係を理解していない.まず、オーバーライド(override)とオーバーロード(overload)の定義を明確にし、オーバーライドとオーバーロードとは何かを区別します.オーバーライドとは、派生クラスの虚メンバー関数がベースクラスの同名でパラメータが同じメンバー関数をオーバーライドすることです.次の例を示します.
class CBase
{
public:
    CBase();
    virtual void Walk(){cout<<"CBase:Walk"<<endl;}
    virtual void Jump(){cout<<"CBase:Jump"<<endl;}
};
class CDerivedA : public CBase
{
public:
    CDerivedA();
    void Walk(){cout<<"CDerivedA:Walk"<<endl;}
    void Jump(){cout<<"CDerivedA:Jump"<<endl;}
};
int main()
{
    CBase *pTmp1=new CDerivedA ;
    pTmp1->Walk();

    return 0;
}
 
 

上例中,CDerived和CBase之间就是函数覆盖关系,Walk和Jump函数被派生类覆盖,输出肯定是派生类函数的输出。下面就这几者关系着重学习。再看看下例:

class CBase
{
public:
    CBase();
    virtual void Walk(){cout<<"CBase:Walk"<<endl;}
    virtual void Jump(){cout<<"CBase:Jump"<<endl;}
    void Run(int speed){cout<<"CBase:Run:"<<"Speed="<<speed<<endl;}
};
class CDerivedA : public CBase
{
public:
    CDerivedA();
    void Walk(){cout<<"CDerivedA:Walk"<<endl;}
    void Jump(){cout<<"CDerivedA:Jump"<<endl;}
    void Run(int speed) {cout<<"CDerivedA:Run"<<"Speed="<<speed<<endl;}
};
int main()
{
    CBase *pTmp1=new CDerivedA ;
    pTmp1->Walk();
    pTmp1->Run(20);
    return 0;
}
ここでベースクラス中のRunと派生クラス中のRun関数はリロード(overoad)関係であり、ベースクラスを使用して派生クラスオブジェクト中のリロード関数を呼び出すと、ベースクラスCBaseのように、その役割ドメインはCBaseというクラスの括弧に含まれる内容であり、派生クラスCDeriverdAの役割ドメインはCDerivedAの括弧に含まれる内容であると、その役割ドメインに基づいて判断される.したがって、ベースクラスを使用して派生クラスオブジェクトのRunメソッドを呼び出すと、ベースクラスのRunメソッドが実行されます.
役割ドメインの可視性ルールについて(ネット上で以下を参照:http://www.51laifu.cn/archives/2012/610/article-31092.html)は次のとおりです.
関係を含む2つ以上の役割ドメインが存在する場合、外層は識別子を宣言し、内層は再び同名識別子を宣言しない場合、外層識別子は内層で依然として表示され、内層で同名識別子を宣言すると、外層識別子は内層では表示されず、内層識別子は外層同名識別子を非表示にする.この現象を非表示規則と呼ぶ.
クラスの派生階層では、ベースクラスのメンバーと派生クラスの新規メンバーにクラス役割ドメインがあります.両者の作用範囲は異なり,互いに含まれる2つの層であり,派生クラスは内層にある.この場合、派生クラスがベースクラスのメンバーと同じ名前の新しいメンバーを宣言すると、派生した新しいメンバーは外層の同じ名前のメンバーを非表示にし、直接メンバー名を使用して派生クラスのメンバーにのみアクセスできます.派生クラスにベースクラスと同じ名前の新しい関数が宣言されている場合、関数のパラメータテーブルが異なる場合でも、ベースクラスから継承された同じ名前の関数のすべてのリロード形式は非表示になります.非表示のメンバーにアクセスするには、クラス役割ドメイン識別子とベースクラス名を使用して定義する必要があります.以上の説明によれば、CBaseクラスは役割ドメインの外層にあるため、派生クラスの方法は可視ではなく、すなわち非表示になる.派生クラスでは、リロード関数がある場合、ベースクラス関数は非表示になります.そうしないと、ベースクラス関数は非表示になりません.
関数のリロードと虚関数は、オブジェクトのマルチステート特性を実現できますが、関数のリロードは静的なマルチステートのみを実現します.つまり、コンパイル時にマルチステートを実現します.つまり、コンパイラは、リロードされた関数にコンパイル時に異なる接頭辞を付けます.関数名が実行時に異なるのです.一方、虚関数は動的多状態、すなわち実行時多状態を実現することができるが、虚関数の実現には追加の虚関数ポインタなどを追加する必要があり、対応する空間が増加する.次の例を見てみましょう.
class CBase
{
public:
    CBase();
    virtual void Walk(){cout<<"CBase:Walk"<<endl;}
    virtual void Jump(){cout<<"CBase:Jump"<<endl;}
    void Run(int speed){cout<<"CBase:Run:"<<"Speed="<<speed<<endl;}
};
class CDerivedA : public CBase
{
public:
    CDerivedA();
    void Walk(){cout<<"CDerivedA:Walk"<<endl;}
    void Jump(){cout<<"CDerivedA:Jump"<<endl;}
    void Run(int speed) {cout<<"CDerivedA:Run"<<"Speed="<<speed<<endl;}
    void Run(int speed,int direction){cout<<"CDerivedA:Run"<<"Speed="<<speed<<";Direction="<<direction<<endl;}
};
int main()
{
    CBase *pTmp1=new CDerivedA ;
    pTmp1->Walk();
    pTmp1->Run(20);
    CDerivedA *pTmp2=(CDerivedA*)pTmp1 ;
    pTmp2->Run(20,3);//   
    //pTmp1->Run(20,3);//   
    return 0;
}
以上のコードから,派生クラスにおけるリロードメソッドは,ベースクラスでは呼び出せず,コンパイル時にエラーが発生することが分かる.
C++でマルチステートを実現する3つの方法:
テンプレート、関数リロード、ダミー関数.
  ,  。。。