2

const-correctnessがどのように機能し、より具体的には、メンバーがcontainerssmart pointersに基づいているクラスを扱う場合、よりよく理解しようとしています。 const-correctnessプロパティは、クラスメンバーに関係なく同じであると思います。しかし、何が起こっているのかを明確に理解するのが難しいので、 私はアドバイスを求めることにしました。スマートポインタでの正確さの正確さ

だから、ここにその文脈があります。私はShapeContainerクラスを持っていて、それはプライベートクラスのメンバとしてスマートポインタのベクトルを持っています。 Shapeクラスは抽象クラスであり、次の仮想関数virtual float doSomething();を持ち、その派生クラスによって再定義されます。これは非constクラス関数であることに注意してください。 は、コードの該当部分を以下に示す:ここでは

class ShapeContainer{ 

    public: 

     typedef std::shared_ptr<Shape> ShapePtr; 
     typedef std::vector<ShapePtr> ShapePtrContainer; 

     // ....... 
     const ShapePtr & operator[](int) const { return m_vect[index]; }; // const version 
     // ShapePtr & operator[](int) { return m_vect[index]; }; // non-const version 
     // ....... 

    private: 

     ShapePtrContainer m_vect; 
}; 

class Shape{ 

    public: 
     // ... 
     virtual float doSomething() = 0; 

}; 

私の質問です。

Q1。なぜ、doSomething()関数をint index = 0; float tmp = container1[index]->doSomething();ShapeContainer container1=createBasicShapes();)と呼ぶことができますか?私が理解から
は、我々はShapeオブジェクトへconstのポインタを取得しますconst ShapePtr operator[] const機能を呼び出した後、しかしdoSomething()仮想 機能はのconstではありません。ですから、constオブジェクトへの参照は非const関数をどのように呼び出すことができますか?

Q2。 operator[]non-constバージョンを追加することによってpreviouly ilustrated(float tmp =container1[index]->doSomething();としてdoSomething()関数を呼び出すことによって、このlatter オーバーロードされたバージョンは、代わりにconst-version一つで呼ばれています。なぜそれはそうですか?

さて、代わりにShapeContainerクラスを有するので、私は今まだvectorを持っていますが(クラスメンバーとしてのスマートポインタを持っている)中間ShapeInfoクラスのShapeContainerInfoという名前の新しいクラスをしました。

class ShapeContainerInfo{ 

    public: 

     typedef std::vector<ShapeInfo> ShapeContainer; 
     const ShapeInfo & operator [](int index) const { return m_vect[index]; }; 
     // ShapeInfo & operator [](int index) { return m_vect[index]; }; // non-const version 

    private: 
     ShapeContainer m_vect; 
}; 

class ShapeInfo{ 

    public: 

     typedef std::shared_ptr<Shape> ShapePtr; 

     // ... 
     float doSomething(){ return m_ShapePtr->doSomething(); }; 

    private: 

     ShapePtr m_ShapePtr; 
     int m_nID; 
}; 

Q3。 float tmp = container2[i].doSomething();を呼び出すと、次のコンパイラエラーが発生します。error C2662: 'ShapeInfo::doSomething' : cannot convert 'this' pointer from 'const ShapeInfo' to 'ShapeInfo &'
しかし、私がnon-constオーバーロードされたoperator []のvesionを追加すると、コンパイラのエラーはなくなります。だから、なぜShapeContainerInfoにはnon-const operator[]が本当に必要で、ShapeContainerには必要ないのですか?

4。 public部材operator[]のみ CONSTバージョンが(ないnon-const 1)で定義した通りであるShapeContainerInfom_vectprivateメンバーは現在設定されている場合、コンパイラエラーメッセージが存在しません。なぜこれ?例えばm_vectをパブリッククラスメンバに設定した後:float tmp = info.m_vect[i].doSomething();

Q5。 ShapeInfoShapeContainerInfoクラスの両方を正しく定義すれば、operator[]const-versionを定義するだけで、まだfloat doSomething()関数を呼び出すことができます。

サンプルコード全体に興味のある方は、hereをご覧ください。
明確化、提案は常に歓迎されます:-) Merci!

答えて

3

Q1:shared_ptrはconstです。つまり、指し示されたオブジェクトがconstであるということではありません。そのためには、shared_ptr<const Shape>が必要です。

Q2:ShapeContainerはconstではなかったので、非const関数はよりよく一致していたので、constバージョンの代わりに呼び出されました。

Q3:vectorは、その要素のconstnessを要素に伝播します。 shared_ptrはそうではありません。これは、配列と生ポインタの動作とインラインである。 const配列の要素はconstです。 constポインタが指すものは必ずしもconstではありません。

Q4:これはエラーが発生しないと言っていますか?

ShapeContainerInfo info; 
info[0].doSomething(); 

エラーであるはずですので、明示してください。

Q4:

ShapeContainerInfo info; 
info.m_vect[0].doSomething(); 

また、それはず:わかりましたので、あなたは、これはエラーを生成しないことを言っています。ベクトルはconstではありません。 constメンバ関数内では、ベクトル(および他のすべてのメンバ)がconstとして扱われます。

Q5:m_vectを一意のポインタのベクトルにします。 const関数の内部では、ベクトル自体がconstになり、一意のポインタはconstになります。しかし、一意のポインターが指すオブジェクトは変更可能です。

例として、このクラスのセット機能が有効ではありません。

struct Foo 
{ 
    void set(int index, int value) const 
    { 
     v[index] = value; 
    } 

    std::vector<int> v; 
};  

しかし、これは次のとおりです。ベンジャミン、感謝@

struct Foo 
{ 
    void set(int index, int value) const 
    { 
     *v[index] = value; 
    } 

    std::vector<std::unique_ptr<int>> v; 
};  
+0

。 'Q3'の答えに関して、私は' std :: vector'を 'non-const'と定義しました。あるいは、正確にどこの' vector'が 'const'と見なされるのでしょうか? Q4/Q5の提案はありますか? – Tin

+0

@Tin:メンバ関数がconstなので、クラスのすべてのメンバはその関数内のconstとみなされます。私はまだQ5を分析しています。 –

+0

@ Benjamin、実際はそうではありません。私がしたのは:float tmp = info.m_vect [i] .doSomething();この場合、私はm_vectをprivateクラスではなくpublicクラスメンバに設定しました。それに加えて、私は演算子[]の 'constバージョン 'だけを考えました。 – Tin