logo

Kopírovat konstruktor v C++

Předpoklad: Konstruktor v C++

A kopírovací konstruktor je členská funkce, která inicializuje objekt pomocí jiného objektu stejné třídy. Jednoduše řečeno, konstruktor, který vytvoří objekt jeho inicializací s objektem stejné třídy, který byl vytvořen dříve, se nazývá kopírovací konstruktor .



Konstruktor kopírování se používá k inicializaci členů nově vytvořeného objektu zkopírováním členů již existujícího objektu.

Konstruktor kopírování bere jako argument odkaz na objekt stejné třídy.

Sample(Sample &t) { id=t.id; }>

Proces inicializace členů objektu prostřednictvím konstruktoru kopírování je známý jako inicializace kopírování.



Nazývá se také inicializace po členech, protože konstruktor kopírování inicializuje jeden objekt s existujícím objektem, přičemž oba patří do stejné třídy na základě kopie člena po členu.

Kopírovací konstruktor může být explicitně definován programátorem. Pokud konstruktor kopírování nedefinuje programátor, udělá to za nás kompilátor.

Příklad:



seznam států
Syntaxe Copy Constructor s příkladem

Syntaxe Copy Constructor

C++




#include> #include> using> namespace> std;> class> student {> >int> rno;> >char> name[50];> >double> fee;> public>:> >student(>int>,>char>[],>double>);> >student(student& t)>// copy constructor> >{> >rno = t.rno;> >strcpy>(name, t.name);> >fee = t.fee;> >}> >void> display();> };> student::student(>int> no,>char> n[],>double> f)> {> >rno = no;> >strcpy>(name, n);> >fee = f;> }> void> student::display()> {> >cout << endl << rno <<>' '> << name <<>' '> << fee;> }> int> main()> {> >student s(1001,>'Manjeet'>, 10000);> >s.display();> >student manjeet(s);>// copy constructor called> >manjeet.display();> >return> 0;> }>

>

>

Výstup

 1001 Manjeet 10000 1001 Manjeet 10000>

C++




#include> #include> using> namespace> std;> class> student {> >int> rno;> >char> name[50];> >double> fee;> public>:> >student(>int>,>char>[],>double>);> >student(student& t)>// copy constructor (member wise> >// initialization)> >{> >rno = t.rno;> >strcpy>(name, t.name);> >}> >void> display();> >void> disp() { cout << endl << rno <<>' '> << name; }> };> student::student(>int> no,>char> n[],>double> f)> {> >rno = no;> >strcpy>(name, n);> >fee = f;> }> void> student::display()> {> >cout << endl << rno <<>' '> << name <<>' '> << fee;> }> int> main()> {> >student s(1001,>'Manjeet'>, 10000);> >s.display();> >student manjeet(s);>// copy constructor called> >manjeet.disp();> >return> 0;> }>

>

>

Výstup

 1001 Manjeet 10000 1001 Manjeet>

Charakteristika Copy Constructor

1. Kopírovací konstruktor se používá k inicializaci členů nově vytvořeného objektu zkopírováním členů již existujícího objektu.

2. Konstruktor kopírování bere jako argument odkaz na objekt stejné třídy. Pokud předáte objekt podle hodnoty v konstruktoru kopírování, bude to mít za následek rekurzivní volání samotného konstruktoru kopírování. K tomu dochází, protože předávání hodnoty zahrnuje vytváření kopie a vytváření kopie zahrnuje volání konstruktoru kopírování, což vede k nekonečné smyčce. Použití odkazu zabrání této rekurzi. Takže používáme referenci objektů, abychom se vyhnuli nekonečným voláním.

Sample(Sample &t) { id=t.id; }>

3. Proces inicializace členů objektu pomocí konstruktoru kopírování je známý jako inicializace kopírování.

4 . Nazývá se také inicializace po členech, protože konstruktor kopírování inicializuje jeden objekt s existujícím objektem, přičemž oba patří do stejné třídy na základě kopie člen po členu.

5. Kopírovací konstruktor může být explicitně definován programátorem. Pokud konstruktor kopírování nedefinuje programátor, udělá to za nás kompilátor.

Příklad:

C++




java barvy

// C++ program to demonstrate the working> // of a COPY CONSTRUCTOR> #include> using> namespace> std;> class> Point {> private>:> >int> x, y;> public>:> >Point(>int> x1,>int> y1)> >{> >x = x1;> >y = y1;> >}> >// Copy constructor> >Point(>const> Point& p1)> >{> >x = p1.x;> >y = p1.y;> >}> >int> getX() {>return> x; }> >int> getY() {>return> y; }> };> int> main()> {> >Point p1(10, 15);>// Normal constructor is called here> >Point p2 = p1;>// Copy constructor is called here> >// Let us access values assigned by constructors> >cout <<>'p1.x = '> << p1.getX()> ><<>', p1.y = '> << p1.getY();> >cout <<>' p2.x = '> << p2.getX()> ><<>', p2.y = '> << p2.getY();> >return> 0;> }>

>

>

Výstup

p1.x = 10, p1.y = 15 p2.x = 10, p2.y = 15>

Typy kopírovacích konstruktorů

1. Výchozí konstruktor kopírování

Implicitně definovaný konstruktor kopírování zkopíruje základy a členy objektu ve stejném pořadí, v jakém by konstruktor inicializoval základy a členy objektu.

C++




// Implicit copy constructor Calling> #include> using> namespace> std;> class> Sample {> >int> id;> public>:> >void> init(>int> x) { id = x; }> >void> display() { cout << endl <<>'ID='> << id; }> };> int> main()> {> >Sample obj1;> >obj1.init(10);> >obj1.display();> >// Implicit Copy Constructor Calling> >Sample obj2(obj1);>// or obj2=obj1;> >obj2.display();> >return> 0;> }>

>

>

Výstup

 ID=10 ID=10>

2. Uživatelsky definovaný konstruktor kopírování

Uživatelsky definovaný konstruktor kopírování je obecně potřeba, když objekt vlastní ukazatele nebo nesdílené odkazy, například na soubor, v takovém případě by měl být zapsán také destruktor a operátor přiřazení.

C++




// Explicitly copy constructor Calling> #include> using> namespace> std;> class> Sample {> >int> id;> public>:> >void> init(>int> x) { id = x; }> >Sample() {}>// default constructor with empty body> >Sample(Sample& t)>// copy constructor> >{> >id = t.id;> >}> >void> display() { cout << endl <<>'ID='> << id; }> };> int> main()> {> >Sample obj1;> >obj1.init(10);> >obj1.display();> >Sample obj2(> >obj1);>// or obj2=obj1; copy constructor called> >obj2.display();> >return> 0;> }>

>

>

Výstup

 ID=10 ID=10>

C++




// C++ Programt to demonstrate the student details> #include> #include> using> namespace> std;> class> student {> >int> rno;> >string name;> >double> fee;> public>:> >student(>int>, string,>double>);> >student(student& t)>// copy constructor> >{> >rno = t.rno;> >name = t.name;> >fee = t.fee;> >}> >void> display();> };> student::student(>int> no, string n,>double> f)> {> >rno = no;> >name = n;> >fee = f;> }> void> student::display()> {> >cout << endl << rno <<>' '> << name <<>' '> << fee;> }> int> main()> {> >student s(1001,>'Ram'>, 10000);> >s.display();> >student ram(s);>// copy constructor called> >ram.display();> >return> 0;> }>

>

>

Výstup

 1001 Ram 10000 1001 Ram 10000>

Kdy se volá konstruktor kopírování?

V C++ může být Copy Constructor volán v následujících případech:

  • Když je objekt třídy vrácen hodnotou.
  • Když je objekt třídy předán (funkci) hodnotou jako argument.
  • Když je objekt vytvořen na základě jiného objektu stejné třídy.
  • Když kompilátor vygeneruje dočasný objekt.

Není však zaručeno, že ve všech těchto případech bude zavolán konstruktor kopírování, protože standard C++ umožňuje kompilátoru optimalizovat kopii v určitých případech, například optimalizace návratové hodnoty (někdy označované jako RVO).

Kopírovat Elision

V copy elision kompilátor zabraňuje vytváření dalších kopií, což má za následek úsporu místa a lepší složitost programu (jak času, tak prostoru); Tím je kód optimalizován.

Příklad:

C++




// C++ program to demonstrate> // the working of copy elision> #include> using> namespace> std;> class> GFG {> public>:> >void> print() { cout <<>' GFG!'>; }> };> int> main()> {> >GFG G;> >for> (>int> i = 0; i <= 2; i++) {> >G.print();> >cout <<>' '>;> >}> >return> 0;> }>

>

>

převést str na int
Výstup

 GFG! GFG! GFG!>

Nyní je na kompilátoru, aby se rozhodl, co chce vytisknout, může buď vytisknout výše uvedený výstup, nebo vytisknout případ 1 nebo případ 2 níže, a to je to, co Optimalizace návratové hodnoty je. jednoduchými slovy, RVO je technika, která dává kompilátoru nějakou další sílu k ukončení vytvořeného dočasného objektu, což má za následek změnu pozorovatelného chování/charakteristiky finálního programu.

Případ 1:

GFG! GFG!>

Případ 2:

GFG!>

Kdy je potřeba uživatelsky definovaný konstruktor kopírování?

Pokud nedefinujeme náš vlastní kopírovací konstruktor, kompilátor C++ vytvoří výchozí kopírovací konstruktor pro každou třídu, který provádí kopírování po členech mezi objekty. Konstruktor kopií vytvořený kompilátorem funguje obecně dobře. Potřebujeme definovat vlastní konstruktor kopírování pouze v případě, že objekt má ukazatele nebo jakékoli přidělení zdroje za běhu popisovač souboru , připojení k síti atd.

Výchozí konstruktor provádí pouze mělkou kopii.

mělká kopie v C++

Hluboké kopírování je možné pouze s uživatelem definovaným konstruktorem kopírování. V uživatelsky definovaném konstruktoru kopírování se ujistíme, že ukazatele (nebo odkazy) zkopírovaných objektů ukazují na nová místa v paměti.

Deep Copy v C++

Kopírovat konstruktor vs operátor přiřazení

Hlavní rozdíl mezi Copy Constructor a Assignment Operator je v tom, že Copy konstruktor vytváří nové paměťové úložiště pokaždé, když je voláno, zatímco operátor přiřazení nevytváří nové paměťové úložiště.

Který z následujících dvou příkazů volá konstruktor kopírování a který operátor přiřazení?

MyClass t1, t2; MyClass t3 = t1; // ---->(1) t2 = ti; // -----> (2)>

Kopírovací konstruktor je volán, když je vytvořen nový objekt z existujícího objektu, jako kopie existujícího objektu. Operátor přiřazení je volán, když je již inicializovanému objektu přiřazena nová hodnota z jiného existujícího objektu. Ve výše uvedeném příkladu (1) volá konstruktor kopírování a (2) volá operátor přiřazení. Další podrobnosti naleznete zde.

Příklad – Třída, kde je vyžadován kopírovací konstruktor

Následuje kompletní program C++, který demonstruje použití konstruktoru Copy. V následující třídě String musíme napsat kopírovací konstruktor.

Příklad:

C++




alya manasa
// C++ program to demonstrate the> // Working of Copy constructor> #include> #include> using> namespace> std;> class> String {> private>:> >char>* s;> >int> size;> public>:> >String(>const> char>* str = NULL);>// constructor> >~String() {>delete>[] s; }>// destructor> >String(>const> String&);>// copy constructor> >void> print()> >{> >cout << s << endl;> >}>// Function to print string> >void> change(>const> char>*);>// Function to change> };> // In this the pointer returns the CHAR ARRAY> // in the same sequence of string object but> // with an additional null pointer ' '> String::String(>const> char>* str)> {> >size =>strlen>(str);> >s =>new> char>[size + 1];> >strcpy>(s, str);> }> void> String::change(>const> char>* str)> {> >delete>[] s;> >size =>strlen>(str);> >s =>new> char>[size + 1];> >strcpy>(s, str);> }> String::String(>const> String& old_str)> {> >size = old_str.size;> >s =>new> char>[size + 1];> >strcpy>(s, old_str.s);> }> int> main()> {> >String str1(>'GeeksQuiz'>);> >String str2 = str1;> >str1.print();>// what is printed ?> >str2.print();> >str2.change(>'techcodeview.com'>);> >str1.print();>// what is printed now ?> >str2.print();> >return> 0;> }>

>

>

Výstup

GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>

Jaký by byl problém, kdybychom odstranili konstruktor kopírování z výše uvedeného kódu?

Pokud z výše uvedeného programu odstraníme konstruktor kopírování, nezískáme očekávaný výstup. Změny provedené v str2 se odrážejí také v str1, což se nikdy neočekává.

C++




#include> #include> using> namespace> std;> class> String {> private>:> >char>* s;> >int> size;> public>:> >String(>const> char>* str = NULL);>// constructor> >~String() {>delete>[] s; }>// destructor> >void> print() { cout << s << endl; }> >void> change(>const> char>*);>// Function to change> };> String::String(>const> char>* str)> {> >size =>strlen>(str);> >s =>new> char>[size + 1];> >strcpy>(s, str);> }> // In this the pointer returns the CHAR ARRAY> // in the same sequence of string object but> // with an additional null pointer ' '> void> String::change(>const> char>* str) {>strcpy>(s, str); }> int> main()> {> >String str1(>'GeeksQuiz'>);> >String str2 = str1;> >str1.print();>// what is printed ?> >str2.print();> >str2.change(>'techcodeview.com'>);> >str1.print();>// what is printed now ?> >str2.print();> >return> 0;> }>

>

>

Výstup:

GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>

Můžeme udělat kopírovací konstruktor soukromým?

Ano, kopírovací konstruktor může být soukromý. Když uděláme konstruktor kopírování soukromým ve třídě, objekty této třídy se stanou nekopírovatelnými. To je zvláště užitečné, když má naše třída ukazatele nebo dynamicky alokované zdroje. V takových situacích můžeme buď napsat vlastní konstruktor kopírování, jako je výše uvedený příklad String, nebo vytvořit konstruktor soukromé kopie, aby uživatelé za běhu dostávali chyby kompilátoru spíše než překvapení.

Proč musí být argument konstruktoru kopie předán jako odkaz?

Kopírovací konstruktor je volán, když je objektu předán hodnotou. Samotný konstruktor kopírování je funkcí. Pokud tedy předáme argument hodnotou v konstruktoru kopírování, provede se volání konstruktoru kopírování, aby se zavolal konstruktor kopírování, což se stane neukončujícím řetězcem volání. Kompilátor proto neumožňuje předávání parametrů hodnotou.

Proč by argument pro konstruktor kopírování měl být const?

Jeden důvod, proč projít konst odkaz je, že bychom měli používat konst v C++ všude, kde je to možné, aby nedošlo k náhodné změně objektů. To je jeden dobrý důvod pro předání odkazu jako konst , ale je v tom víc než „ Proč by argument pro konstruktor kopírování měl být const?‘