プライベート虚関数の特徴(C++とJavaのメカニズムはまだ異なる)

6218 ワード

多態性は多態を実現する関数のアクセス制限子とは何の関係もなくprivate関数は依然として多態を実現することができ、そのポインタは依然としてvtblの中に位置しているが、この関数の多態は一般的にベースクラスの内部で他の非虚関数によって呼び出されたときにのみ反映され、アクセス制限子は外部のクラスのメンバーへのアクセス権限だけを制限し、次のルールは破壊されません.
ベースクラスポインタまたは参照によってメンバー関数を呼び出す場合、その関数が虚でない場合、静的バインド、すなわちコンパイル時バインドが採用されます.この関数が仮想である場合、動的バインド、すなわち実行時バインドが使用されます.
#include <string>
#include <iostream>
using namespace std ;

class Base
{
private:
    virtual string classID() const
    {
       return string("Base") ;
    }

protected:
    virtual void doWork() =0 ; //     

public:
    void work()
    {
        cout<<"this class id is "<< classID() <<endl ; //        
        doWork() ; //       
    }

    virtual ~Base()
    {
    }
};

class DerivedA : public Base
{
private:
    string classID() const
    {
       return string("DerivedA") ;
    }

protected:
    void doWork()
    {

       cout<<"this is DerivedA doWork !"<<endl ;
    }
};

int main()
{
    Base* bp = new DerivedA() ;
    bp->work() ;
    delete bp ;
}

実行結果:this class id is DelivedAthis is DelivedA doWork!
ClassIDはprivateですが、マルチステートが実現されています(この関数をpublicと宣言した結果と同じです).この関数はvirtualだからです.ベースクラスポインタまたは参照を使用して虚関数呼び出しを行うには、動的バインドが使用されます.コンパイラがclassIDを呼び出すために生成したコードを見てみましょう.
//c++ダミー
(this->vptr[1])() ;
実行時には、thisポインタで正しいvtbl、すなわちDerivedAクラスのvtblが見つかり、自然に上記の結果が表示されます.ではclassIDをprivateと宣言すると何が制限されますか?非虚関数をprivateとして宣言するのと同様に、ワーク関数呼び出しなどのBaseクラスの外部でマルチステート関数classIDを呼び出すことはできません.
参照先:http://www.dewen.io/q/8738/%E7%A7%81%E6%9C%89%E7%BA%AF%E8%99%9A%E5%87%BD%E6%95%B0%E7%9A%84%E4%BD%9C%E7%94%A8%EF%BC%9F
------------------------------------------------------------------------------
新しい意見:
これは確かにc++自体の矛盾しているところだと思います.その多重継承のように、private関数を虚関数に設定するのは少し乱れています.もちろん例はdemoにすぎません.問題を説明しましたが、実際の運用ではprivateを虚関数に設定するのはよくないと思います.私の論拠はjavaです.
Javaではpublic,protected,friendly関数は自動的に多態化できる(virtualなどの言葉を付けなくてもいい)が、関数をprivateに設定するとfinalであることが隠されており、finalは布団類の書き換えが許されないため多態化が拒否される場合がある.Javaが分からなくても大丈夫です.javaはc++よりooに合った言語としてprivate関数の多態性を取り除くには道理があるに違いありません.
参照先:http://bbs.csdn.net/topics/60083939
public class Polymorphism {
    private void show()
    {
        print("show parent");
    }
    public static void main(String[] args)
    {
        Polymorphism p=new privateMethod();
        p.show();
    }
}
class privateMethod extends Polymorphism
{
    public void show()
    {
        print("show derived");
    }
}

出力結果:結果はshow parentです.Javaではプライベートメソッドを書き換えることはできませんが、これは実はよく理解されています.プライベートメソッドはサブクラスでは見えないからです.子クラスには親を継承するプライベートメソッドがなく、書き換えることはできません.したがって、サブクラスでの同名メソッドは新しいメソッドです.
参照先:http://www.cnblogs.com/developerY/p/3421711.html