티스토리 뷰

반응형

05-1 복사 생성자는 왜 필요한가?

 C++ 스타일의 초기화

int num=20;

int &ref=num;

우리는 이렇게 초기화했지만 다음 방법도 가능하다.

int num(20);

int &ref(num);

 

class SoSimple

{

private:

 int num1;

 int num2;

};

 

SoSimple=sim1;

SoSimple sim2=sim1;

 

sim2 num1 <- sim1 num1

sim2 num2 <- sim1 num2

 

 SoSimple sim2(sim1);

이 문장에 담겨 있는 의미를 생각해보자.

 SoSimple형 객체를 생성해라.

 객체의 이름을 sim2로 정한다.

 sim1을 인자로 받을 수 있는 생성자의 호출을 통해 객체생성을 완료한다.

 

복사생성자는 호출시점이 일반 생성자와 차이가 있다.

-> 호출시점을 잘 아는 게 중요하다.

 

 자동으로 삽입이 되는 디폴트 생성자

'복사 생성자를 정의하지 않으면, 멤버 대 멤버 복사를 진행하는 디폴트 복사 생성자가 자동으로 삽입된다.'

 

 변환에 의한 초기화! 키워드 explicit으로 막을 수 있다.

SoSimple sim2=sim1;

이 경우 묵시적 변환이 일어나서 복사 생성자가 호출된다.

 

explicit Sosimple(const SoSimple &copy)

 :num1(copy.num1), num2(copy.num2)

{

//empty!

}

더 이상 묵시적 변환이 발생하지 않아서 대입 연산자를 이용한 객체의 생성 및 초기화는 불가능하다.

 

AAA obj=3; //AAA obj(3); 으로 변환

explicit이 있을 경우

AAA obj(3); 

-> 이 형태로만 객체 생성을 할 수 있다.

 

참고 복사 생성자의 매개변수는 반드시 참조형이어야 하는가?

 

 

05-2 '깊은 복사'와 '얕은 복사'

 디폴트 복사 생성자의 문제점

#include <iostream>
#include <cstring>
using namespace std;


class Person
{
private:
	char* name;
	int age;
public:
	Person(char* myname, int myage)
	{
		int len = strlen(myname) + 1;
		name = new char[len];
		strcpy(name, myname);
		age = myage;
	}
	void ShowPersonInfo() const
	{
		cout << "이름: " << name << endl;
		cout << "나이: " << age << endl;
	}
	~Person()
	{
		delete[]name;
		cout << "called destructor!" << endl;
	}
};

int main(void)
{
	Person man1("Lee dong woo", 29);
	Person man2 = man1;
	man1.ShowPersonInfo();
	man2.ShowPersonInfo();
	return 0;
}

 

called destructor! 가 두번 호출 되어야 하는데 한 번만 호출된다.

 

man1 -> Lee dong woo <-man2

 

둘다 같은 Lee dong woo를 참조하고 있다가, Lee dong woo가 삭제되기 때문에 문제가 발생한다.

그렇기에 man2가 참조하던 문자열도 없어진다.

 

 '깊은 복사'를 위한 복사 생성자의 정의

Person(const Person& copy):age(copy.age)

{

 name=new char[strlen(copy.name)+1];

 strcpy(name,copy.name);

}

 

멤버 변수 age의 멤버 대 멤버 복사

메모리 공간 할당후 문자열 복사, 그리고 할당된 메모리의 주소 값을 멤버 name에 저장

 

 

05-3 복사생성자의 호출시점

 복사 생성자가 호출되는 시점은?

case 1: 기존에 생성된 객체를 이용하여 새로운 객체를 초기화하는 경우(앞서 보인 경우)

case 2: call-by-value 방식의 함수호출 과정에서 객체를 인자로 전달하는 경우

case 3: 객체를 반환하되, 참조형으로 반환하지 않는 경우

 

공통점

객체를 새로 생성해야 한다. 단 생성과 동시에 자료형의 객체로 초기화해야한다.

 

 메모리 공간의 할당과 초기화가 동시에 일어나는 상황

매개변수 호출 시 메모리 할당

반환시 메모리 할당

 

 할당 이후 복사생성자를 위한 통한 초기화

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;


class Temporary
{
private:
	int num;
public:
	Temporary(int n) : num(n)
	{
		cout << "create obj: " << num << endl;
	}
	~Temporary()
	{
		cout << "destroy obj " << num << endl;
	}
	void ShowTempInfo()
	{
		cout << "My num is " << num << endl;
	}
};

int main(void)
{
	Temporary(100);
	cout << "*********** after make!" << endl << endl;

	Temporary(200).ShowTempInfo();
	cout << "************* after make!" << endl << endl;;

	const Temporary& ref = Temporary(300);
	cout << "***************** end of main!" << endl<<endl;
	return 0;

}

after make란 말이 나오기 전에 이미 소멸한 것을 보여준다.

 

-임시객체는 다음 행으로 넘어가면 바로 소멸되어 버린다.

-참조자에 참조되는 임시객체는 바로 소멸되지 않는다.

 

05-4 OOP 단계별 프로젝트 03단계

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함
반응형