0

オブジェクトのスライスを使用したいコードのケースがありますが、それが安全か賢明かを判断しようとしています。これを判断するために、次の例を実行しました。

#include <iostream>

using namespace std;


class Dog{

    public:
        Dog( int x )
            :x{x}
        {

        };

        int x;

};


class Spaniel: public Dog{

    public:
        Spaniel( int x, int y )
            :Dog{x}, y{y}
        {

        }

        int y;

};


class Green{

    public:
     Green( int q )
         :q{q}
     {

     }

     int q;

};


class GreenSpaniel: public Spaniel, public Green{

   public:
        GreenSpaniel( int x, int y, int q, int z )
            :Spaniel{x,y}, Green{q}, z{z}
        {

        }

        int z;

};



int main(){

    GreenSpaniel jerry{ 1,2,3,4 };

    Green fred = jerry;

    cout << fred.q << endl;  //correctly displays "3"

    return 0;

}

基本クラスが最上位 (ルート) ではないため、1 が返されることを期待していましたが、3 が表示されます。クラスのいずれかに仮想テーブルがある場合、あなたの答えはどのように変わりますか? 安全だと思わない場合、派生オブジェクトから非ルート ベース オブジェクトをコピーするための回避策はありますか?

次のコマンドを使用して、gcc 4.6.3 の Linux でこれを実行しました。

g++ -std=c++0x main.cc
4

1 に答える 1

4

何が起こっているかというと、コンパイラによって合成されたコピー コンストラクターを使用して fred が構築されており、これがconst Green&引数として使用されています。jerry の Green 部分のコンテンツの浅いコピーを実行します。

を使用した場合、同じ結果が表示されます。

const Green& fred = jerry;

コピーが実行されていない場合は、名前を付けて jerry の jerry 部分にアクセスしているだけですfred

質問の他の部分については、あなたの設計に安全でないものは何もありません.ただ「複雑」であり、何が起こっているのかを認識する必要があります. このトピックに関する議論については、このページと関連ページを読むことをお勧めします。

もちろん、異なる動作を持つ独自のコピー コンストラクター/オペレーターを定義できます。または、コンパイラがそれらを生成するのを禁止することもできます

これらに対処する従来の方法は、プライベート コピー コンストラクターとコピー代入を宣言し、その理由を文書化することです。C++ 2011 では、コピー コンストラクターとコピー代入演算子を宣言し、両方を削除済みとしてマークする新しい代替手段が導入されました。noncopyable からの派生は、より単純で明確であり、追加のドキュメントは必要ありません。

ソース

于 2013-07-23T08:36:06.487 に答える