2017-02-08 6 views
1

私はプログラミングの初心者です。私はコピーコンストラクタについて学んでいます。さまざまなソースから、クラスオブジェクトを「ディープコピー」して、新しいオブジェクトのポインタメンバーが新しいメモリ位置を指すようにするには、コピーコンストラクタが便利であることがわかります。コピーコンストラクタとダイナミックメモリ

私の質問では、空のコピーコンストラクタ(EmptyCatクラスの場合)と同じ結果が得られた場合、私の例のCopyCatクラスのようにコピーコンストラクタを定義する利点は何ですか?

私の2番目の質問は、なぜCatクラスとEmptyCatクラスが違うのですか?それらの唯一の違いは、EmptyCatに空のコピーコンストラクタを定義することです。しかし私がプログラムを実行すると、コピー後のEmptyCatで、ポインタ・メンバーが新しい場所を指しているのに対して、クラスCatではそれは浅いコピーとして機能することがわかります。私は、プログラムを実行する場合

#include "iostream" 

class Cat 
{ 
    public: 
    void GetMem() { std::cout << itsAge << "\n"; } 
    private: 
    int * itsAge = new int; 
}; 

class EmptyCat 
{ 
    public: 
    EmptyCat() {} 
    ~EmptyCat() {} 
    EmptyCat(EmptyCat&obj) {} 
    void GetMem() { std::cout << itsAge << "\n"; } 
    private: 
    int * itsAge = new int; 
}; 

class CopyCat 
{ 
    public: 
    CopyCat() {} 
    ~CopyCat() {} 
    CopyCat(CopyCat&obj); 
    int GetAge() { return *itsAge; } 
    void GetMem() { std::cout << itsAge << "\n"; } 
    private: 
    int * itsAge = new int; 
}; 

CopyCat::CopyCat(CopyCat & obj) 
{ 
    itsAge = new int; 
    *itsAge = obj.GetAge(); 
} 

int main() 
{ 
    Cat Garfield; 
    Cat Kitty(Garfield); 

    std::cout << "Memory addresses for the objects' <itsAge> member:" << std::endl; 
    std::cout << "Garfield and Kitty (Class Cat):" << std::endl; 
    Garfield.GetMem(); 
    Kitty.GetMem(); 

    EmptyCat Meow; 
    EmptyCat Purr(Meow); 

    std::cout << std::endl << "Meow and Purr (Class EmptyCat):" << std::endl; 
    Meow.GetMem(); 
    Purr.GetMem(); 

    CopyCat Fluffy; 
    CopyCat Felix(Fluffy); 

    std::cout << std::endl << "Fluffy and Felix (Class CopyCat):" << std::endl; 
    Fluffy.GetMem(); 
    Felix.GetMem(); 

    system("pause"); 
    return 0; 
} 

私はこれを取得:

Memory addresses for the objects' <itsAge> member: 
Garfield and Kitty (Class Cat): 
00BBDA60 
00BBDA60 

Meow and Purr (Class EmptyCat): 
00BB46A0 
00BB8280 

Fluffy and Felix (Class CopyCat): 
00BB82B0 
00BBE8A0 
Press any key to continue . . . 
+3

クラスのメモリがリークしているので、実際には何の例でもありません。 –

+0

コピーコンストラクタの動作に焦点を絞って、できるだけシンプルにしたいと考えました – SVG

+0

しかし、そうすることで、興味深いものがすべて失われています。あなたのデストラクタが割り当てを削除するならば、あなたはすぐに3つのルールとすべてのルールを発見します。 –

答えて

0

私の質問では、空のコピーコンストラクタ(EmptyCatクラスの場合)と同じ結果が得られた場合、私の例のCopyCatクラスのようにコピーコンストラクタを定義する利点は何ですか?

同じ結果は得られません。 CopyCatは新しいメモリを割り当てますは古いクラスから値をコピーします。 EmptyCatは新しいメモリを割り当てますが、値をコピーしません。

私の2番目の質問は、なぜCatクラスとEmptyCatクラスが違うのですか?それらの唯一の違いは、EmptyCatに空のコピーコンストラクタを定義することです。しかし私がプログラムを実行すると、コピー後のEmptyCatで、ポインタ・メンバーが新しい場所を指しているのに対して、クラスCatではそれは浅いコピーとして機能することがわかります。

Catでは、コピーコンストラクタを宣言していないため、必要なときにコンパイラが生成します。デフォルトのコピーコンストラクタは、元のメンバワイズコピーを行います。あなたの場合、これはポインタをコピーします(オリジナルのものと同じアドレスを保存するように)。

EmptyCatには、ユーザー定義のコピーコンストラクタがあります。しかし、ポインタメンバーを処理しないので、そのデフォルト値が使用されます。

int * itsAge = new int; 

これは新しいintを割り当て、あなたに別のポインタ値を取得するものです。

+0

あなたの答えに基づいて私はいくつかの変更を加えました。私は、空に定義されたコピーコンストラクタがどのように動作するかを示しました。 空の定義を持つコピーコンストラクタはコピーコンストラクタではなく、実際には何もコピーしません。実際には新しいオブジェクト作成として動作します。それは、クラス定義に基づいて新しいオブジェクトを作成するので、クラス定義に 'int * itsAge = new int;'ステートメントがあるので混乱してしまいます(空のコピーコンストラクタが新しいオブジェクト)。 – SVG

+0

私はいくつかのさらなる研究を行い、暗黙コピーコンストラクタ(宣言されたコピーコンストラクタが存在しないときに使用される)が次のようなものであることがわかりました。 'Class :: Class(const Class&object): x暗黙的なコピーコンストラクタは、空に定義されたコピーコンストラクタよりも多くを行います。 – SVG

0

あなたがして、空のコピーコンストラクタなしで同じ動作を取得されていません。 EmptyCat(EmptyCat& obj) { }は何もしません。

CopyCat(CopyCat& obj) { 
    itsAge = new int; 
    *itsAge = obj.GetAge(); 
} 

は動的に新しいintを割り当て、それにobjから値を割り当てます。

0

ディープコピーとシャローコピーは、構造とローポインタのみを持つCの概念です。ポインタを所有することができます。この場合、コピーは深くなければならず、共有することもできます。コピーが浅い場合(そしてmallocで割り当てられている場合は解放するように注意する必要があります)

C++では、newは効果的に廃止されました。私たちは "所有ポインタ"と "共有ポインタ"である一意のポインタを持っています。しかし、ポインタは比較的まれです。クラスの配列メンバーはstd :: vectorsであり、文字列メンバーはstd :: stringsです。コピーは自動的に深くなります(浅いコピーが必要な場合は参照を使用します)。

ポインタは、ツリーやグラフのような比較的特殊な状況のために戻されます。

関連する問題