仮想継承(Virtual Inheritance)

7281 ワード

次の仮想継承を考慮します.
class Point3d: public virtual Point

{

    Point3d(float x = 0.0, float y = 0.0, flloat z = 0.0)

        :Point(x, y). _z(z){}

    Pooint(const Point3d &rhs)

        :Point(rhs), _z(rhs._z){}

    Point3d& operator=(const Point3d&);

    ~Point3d();

    virtual float Z() {return _z;}

protected:

    float _z;

};

従来のconstructor拡張現象は役に立たない.virtual base classの共有性のためだ.
//  constructor  

Point*

Point::Point(Point3d *this,

         float x, float y, float z)

{

    // 

    this->Point::Point(x, y);

    this->__vptr_Point3d = __vtbl_Point3d;

    this->__vptr_Point3d__Point = 

          __vptr_Point3d__Point;

    this->_z = rhs._z;

    return this;

}

上記のPoint 3 d constructor拡張内容に何か間違いがありますか?
これは、私の理解では菱形継承の中で、subobjectは最下層のclassのconstructorを呼び出すことを担当していない.呼び出すclassは菱形の底の近親結婚のclassであるべきで、拡張コードの中にPoint constructorに対する呼び出しがあるべきではない.私も皆さんとこの拡張コードに対するあなたの見方を交流したいです.私の見方の具体的な理由は以下の通りです.
次の3つの派生を考慮します.
class Vertex: virtual public Point{...};

class Vertex3d: public Point3d, public Vertex{...};

class PVertex: public Vertex3d{...};

VertexのconstructorもPointのconstructorを呼び出す必要があります.しかし、Point 3 dとVertexが同じVertex 3 dのsubobjectsである場合、それらのPoint constructorに対する呼び出し操作は起こり得ず、代わりに最下層のclassであり、Vertex 3 dはPointを初期化する責任があり、その後の継承はPVertexによって共有されるPoint subobjectの構造を完成する.virtual base classを初期化するのは、virtual base class constructorが呼び出すべきかどうかを示すために、constructorにより拡張されたコンテンツがより多く含まれるためである.constructorの関数自体は、入力パラメータを条件的にテストし、関連するvirtual base class constructorsを呼び出すかどうかを決定する必要がある.以下はPoint 3 dのconstructor拡張内容です.
Point3d*

Point3d::Point3d(Point3d *this, bool __most_derived, 

         float x, float y, float z)

{

    if(__most_derived != flase){

        this->Point::Point(x, y);

    }



    this-> __vptr_Point3d = __vtbl_Point3d;

    this->__vptr_Point3d__Point = 

          ___vtbl_Point3d__Point;

    this->_z = rhs._z;

    return this;

} 

より深いレベルの場合、例えばVertex 3 dがPoint 3 dとVertexのconstructorを呼び出すと、いつも_most_derivedパラメータをfalseとすることで、2つのconstructorsにおけるPoint constructorに対する呼び出し操作を抑圧する.
//  virtual base class   constructor  

Vertex3d*

Vertex3d::Vertex3d(Vertex3d *this, bool__most_derived

           , float x, float y, float z)

{

    if(__most_derived != false){

        this->Point::Point(x, y);

    }

    

    //  class,  

    this->Point3d::Point3d(false, x, y, z);

    this->Vertex::Vertex(false, x, y);



    //  vptrs

    //  user code



    return this;

}

このような戦略を採用することで、Point 3 d originを定義すると、意味の正確さが保証されます.この場合、Point 3 d constructorは、そのPoint virtual base class subobjectを正しく呼び出すことができるが、Vertex 3 d cvを定義すると、Vertex 3 d constructorは、Point constructorを正しく呼び出す.Point 3 dとVertexのconstructorsはPointの呼び出し操作以外にやるべきことをする.多くの人は、virtual base class constructorsの呼び出しには明確な定義があることに気づいているかもしれません.完全なclass objectが定義されている場合にのみ呼び出されます.objectが完全なobjectのsubobjectである場合、呼び出されません.この点をレバレッジとして、より効率的なconstructorsを生成することができます.いくつかのコンパイラは各constructorを2つに分裂させ、1つは完全なobjectに対して、もう1つはsubobjectに対して.完全なobject版はvirtual base constructorsを無条件に呼び出し、すべてのvptrsなどを設定します.subobject版ではvirtual base constructorsとvptrsは呼び出されません.やはり次のブログでvptrsの設定について議論したいと思います.constructorの分裂は速度の向上をもたらすことができますが、あなたが使っているコンパイラがこの特性をサポートしているかどうかは自分で判断する必要があります.