전제 조건: C++의 생성자
ㅏ 복사 생성자 동일한 클래스의 다른 개체를 사용하여 개체를 초기화하는 멤버 함수입니다. 간단히 말해서, 이전에 생성된 동일한 클래스의 객체로 초기화하여 객체를 생성하는 생성자를 복사 생성자 .
복사 생성자는 이미 존재하는 개체의 멤버를 복사하여 새로 생성된 개체의 멤버를 초기화하는 데 사용됩니다.
복사 생성자는 동일한 클래스의 객체에 대한 참조를 인수로 사용합니다.
Sample(Sample &t) { id=t.id; }>
복사 생성자를 통해 개체의 멤버를 초기화하는 프로세스를 복사 초기화라고 합니다.
복사 생성자가 하나의 개체를 기존 개체로 초기화하기 때문에 멤버별 초기화라고도 합니다. 둘 다 멤버별로 동일한 클래스에 속합니다.
복사 생성자는 프로그래머가 명시적으로 정의할 수 있습니다. 프로그래머가 복사 생성자를 정의하지 않으면 컴파일러가 이를 대신 수행합니다.
예:
공장 디자인 패턴

복사 생성자의 구문
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;> }> |
>
>산출
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;> }> |
>
>산출
1001 Manjeet 10000 1001 Manjeet>
복사 생성자의 특징
1. 복사 생성자는 이미 존재하는 개체의 멤버를 복사하여 새로 생성된 개체의 멤버를 초기화하는 데 사용됩니다.
2. 복사 생성자는 동일한 클래스의 객체에 대한 참조를 인수로 사용합니다. 복사 생성자의 값으로 개체를 전달하면 복사 생성자 자체에 대한 재귀 호출이 발생합니다. 이는 값 전달에 복사본 만들기가 포함되고, 복사본 만들기에는 복사 생성자 호출이 포함되어 무한 루프가 발생하기 때문에 발생합니다. 참조를 사용하면 이러한 재귀를 방지할 수 있습니다. 따라서 무한 호출을 피하기 위해 객체 참조를 사용합니다.
Sample(Sample &t) { id=t.id; }>
삼. 복사 생성자를 통해 객체의 멤버를 초기화하는 프로세스를 복사 초기화.
4 . 복사 생성자가 기존 개체로 하나의 개체를 초기화하기 때문에 멤버별 초기화라고도 합니다. 둘 다 멤버별 복사 기준으로 동일한 클래스에 속합니다.
5. 복사 생성자는 프로그래머가 명시적으로 정의할 수 있습니다. 프로그래머가 복사 생성자를 정의하지 않으면 컴파일러가 이를 대신 수행합니다.
예:
C++
자바 날짜를 문자열로
// 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;> }> |
>
>산출
p1.x = 10, p1.y = 15 p2.x = 10, p2.y = 15>
복사 생성자의 유형
1. 기본 복사 생성자
암시적으로 정의된 복사 생성자는 생성자가 개체의 기본 및 멤버를 초기화하는 것과 동일한 순서로 개체의 기본 및 멤버를 복사합니다.
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;> }> |
>
>산출
ID=10 ID=10>
2. 사용자 정의 복사 생성자
사용자 정의 복사 생성자는 일반적으로 객체가 파일과 같은 공유 불가능한 참조나 포인터를 소유할 때 필요합니다. 이 경우 소멸자와 할당 연산자도 작성해야 합니다.
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;> }> |
>
>산출
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;> }> |
>
>산출
1001 Ram 10000 1001 Ram 10000>
복사 생성자는 언제 호출되나요?
C++에서는 다음과 같은 경우 복사 생성자가 호출될 수 있습니다.
- 클래스의 객체가 값으로 반환되는 경우.
- 클래스의 객체가 값에 의해 인수로 (함수에) 전달되는 경우.
- 동일한 클래스의 다른 객체를 기반으로 객체가 생성되는 경우.
- 컴파일러가 임시 개체를 생성하는 경우.
그러나 이러한 모든 경우에 복사 생성자가 호출된다는 보장은 없습니다. 왜냐하면 C++ 표준에서는 컴파일러가 특정 경우에 복사본을 최적화할 수 있도록 허용하기 때문입니다. 한 가지 예는 다음과 같습니다. 반환 값 최적화 (RVO라고도 함).
복사 제거
복사 제거에서 컴파일러는 추가 복사본 생성을 방지하여 공간을 절약하고 프로그램 복잡성(시간과 공간 모두)을 향상시킵니다. 따라서 코드를 더욱 최적화합니다.
예:
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;> }> |
>
자바 문자열 cmp
>산출
GFG! GFG! GFG!>
이제 무엇을 인쇄할지 결정하는 것은 컴파일러에 있습니다. 위의 출력을 인쇄하거나 아래 사례 1 또는 사례 2를 인쇄할 수 있습니다. 반환 값 최적화 이다. 간단히 말해서, RVO 생성된 임시 개체를 종료할 수 있는 추가 기능을 컴파일러에 제공하여 최종 프로그램의 관찰 가능한 동작/특성을 변경하는 기술입니다.
사례 1:
GFG! GFG!>
사례 2:
GFG!>
사용자 정의 복사 생성자는 언제 필요합니까?
자체 복사 생성자를 정의하지 않으면 C++ 컴파일러는 객체 간에 멤버별 복사를 수행하는 각 클래스에 대한 기본 복사 생성자를 만듭니다. 컴파일러가 생성한 복사 생성자는 일반적으로 잘 작동합니다. 객체에 포인터가 있거나 다음과 같은 리소스의 런타임 할당이 있는 경우에만 자체 복사 생성자를 정의해야 합니다. 파일 핸들 , 네트워크 연결 등
기본값 생성자는 얕은 복사만 수행합니다.
전체 복사는 사용자 정의 복사 생성자를 통해서만 가능합니다. 사용자 정의 복사 생성자에서는 복사된 개체의 포인터(또는 참조)가 새 메모리 위치를 가리키는지 확인합니다.
복사 생성자와 할당 연산자
복사 생성자와 할당 연산자의 주요 차이점은 복사 생성자는 호출될 때마다 새 메모리 저장소를 만드는 반면 할당 연산자는 새 메모리 저장소를 만들지 않는다는 것입니다.
다음 두 명령문 중 복사 생성자를 호출하는 명령문과 할당 연산자를 호출하는 명령문은 무엇입니까?
MyClass t1, t2; MyClass t3 = t1; // ---->(1) t2 = t1; // -----> (2)>
복사 생성자는 기존 개체의 복사본으로 기존 개체에서 새 개체를 만들 때 호출됩니다. 할당 연산자는 이미 초기화된 개체에 다른 기존 개체의 새 값이 할당될 때 호출됩니다. 위의 예에서 (1)은 복사 생성자를 호출하고 (2) 할당 연산자를 호출합니다. 자세한 내용은 여기를 참조하세요.
예 – 복사 생성자가 필요한 클래스
다음은 Copy 생성자의 사용을 보여 주는 완전한 C++ 프로그램입니다. 다음 String 클래스에서는 복사 생성자를 작성해야 합니다.
예:
C++
엑셀로 근속기간 계산하기
// 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;> }> |
>
>산출
GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>
위 코드에서 복사 생성자를 제거하면 어떤 문제가 발생할까요?
위 프로그램에서 복사 생성자를 제거하면 예상한 출력을 얻지 못합니다. str2에 대한 변경 사항은 str1에도 반영되며 이는 전혀 예상치 못한 일입니다.
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;> }> |
>
>
산출:
GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>
복사 생성자를 비공개로 만들 수 있나요?
예, 복사 생성자를 비공개로 설정할 수 있습니다. 클래스에서 복사 생성자를 비공개로 만들면 해당 클래스의 개체는 복사할 수 없게 됩니다. 이는 클래스에 포인터가 있거나 동적으로 할당된 리소스가 있을 때 특히 유용합니다. 이러한 상황에서는 위의 String 예제와 같이 자체 복사 생성자를 작성하거나 사용자가 런타임 시 예상치 못한 컴파일러 오류가 발생하지 않도록 전용 복사 생성자를 만들 수 있습니다.
복사 생성자에 대한 인수를 참조로 전달해야 하는 이유는 무엇입니까?
복사 생성자는 객체가 값으로 전달될 때 호출됩니다. 복사 생성자 자체는 함수입니다. 따라서 복사 생성자에서 값으로 인수를 전달하면 복사 생성자를 호출하여 종료되지 않는 호출 체인이 되는 복사 생성자를 호출하게 됩니다. 따라서 컴파일러는 매개변수가 값으로 전달되는 것을 허용하지 않습니다.
복사 생성자의 인수가 const여야 하는 이유는 무엇입니까?
합격 이유 중 하나 const 참조는 우리가 사용해야한다는 것입니다 const 객체가 실수로 수정되지 않도록 가능하면 C++에서 사용하세요. 이는 참조를 다음과 같이 전달하는 좋은 이유 중 하나입니다. const , 하지만 '보다 더 많은 것이 있습니다. 왜 복사 생성자에 대한 인수는 const여야 합니까?'