hahahia

C++ 복사생성자(생성자에 관한 이해 및 얕은,깊은 복사) 본문

Language/C++

C++ 복사생성자(생성자에 관한 이해 및 얕은,깊은 복사)

hahahia 2012. 10. 20. 12:41

ㅎㅎ시험기간이라 그런지 요즘 학교 후배들이 생성자쪽에 대해서 많이 물어보더라구요...

그래서 한번 복습할겸 포스팅해보겠습니다,


#include <iostream>

using namespace std;

 

int main(){

        int a = 10; // C style

        int b(5); // C++ style

        cout << a << endl;

        cout << b << endl;

        return 0;

}

출력결과 :

10

5 


위 소스를 보게되면 변수 초기화 방법이 두가지가 있다는 것을 볼 수 있는데요 그렇다면 변수가 아닌 객체도 저 두가지 방식으로 초기화를 할 수 있을텐데요. 과연 가능한지 확인해보도록 하겠습니다.


#include <iostream>

using namespace std;


class A{

public:

        A(int _data) { data = _data; } // Constructor

        void getData() { cout << data << endl; }

private:

        int data;

};

int main(){

        A a(5);

        A aa = 5;

 

        a.getData();

        aa.getData();

        return 0;

}

출력결과:

5

5


결과는 모두 5를 출력하겠죠. 그렇기에 객체 또한 초기화 방법이 2가지가 있다는 것을 볼 수 있네요.. 하지만 위에서 A aa = 5; 는 컴파일을 하는 동시에 A aa(5); 로 변환이 이루어지는 과정이기 때문에 동 일하다고 볼수 없네요. 아래 소스를 한번 보도록 하겠습니다.


 #include <iostream>

#include <string>

using namespace std;

 

class A{

public:

        A(char* _data){ strcpy(data, _data); }

        void getData() { cout << data << endl; }

private:

        char data[100];

};

 

int main(){

        A a("Inha Univ.");

        A aa(a); // ?? char * 값이 아닌 객체를 넘겨받았는데 초기화가 되네요

 

        a.getData();

        aa.getData();

 

        return 0;

}

 

출력결과:

Inha Univ.

Inha Univ.


위 소스에서 보면 A 자료형을 받는 생성자 함수를 만들지 않았지만 자동으로 만들어졌다고 생각할 수 밖에 없는데 우리는 이런 자기 자신과 같은 형태의 객체를 인자로 받을 수 있는 생성자가 자동으로 만들어진것을 디폴트 복사 생성자라 합니다. 

자 여기서 복사생성자에 대해서 한번 정의를 해보도록 하겠습니다. 복사 생성자란 자기 자신과 같은 형태의 객체를 받는 것입니다. 

그렇다면 디폴트 복사 생성자라는것이 멤버 변수들을 복사하는 것일텐데 클래스마다 가지고있는 데이터들이 다르기 때문에 디폴트 생성자는 각 클래스마다 다른 형태로 바뀌어서 복사가 된다고 볼 수 있다. 

따라서 매우 편리해보이는 이 디폴트 생성자는 큰 문제점이 존재합니다


 

#include<iostream>

#include<string>

using namespace std;

 

class A{

private:

    char *name; // 값을 참조하는 방식으로..

    char *phone;

    int age;

public:

    A(char *_name, char* _phone, int _age){

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

        strcpy(name,_name);

        phone = new char[strlen(_phone)+1];

        strcpy(phone,_phone);

        age = _age;

    }

    void output(){

        cout<<name<<endl;

        cout<<phone<<endl;

        cout<<age<<endl;

    }

    void modify(char *val){

        strcpy(name,val);

    }

    ~A(){

        delete []name;

        delete []phone;

    }  // 동적할당을 해제

};

 

int main(){

    A *a = new A("Hahahia","010",21);

    A b(*a);

 

 

    a->output();

    a->modify("qwerty");

    b.output();

    delete a;

    b.output();

    return 0;

}

 

 



저렇게 에러메시지가 딱 나타나버렸네요.. 말그대로, 디폴트 복사 생성자는 직접 값을 복사하는것이 아니라 "참조"를 하고 있던거였네요 이를 얕은 복사라 하며, 객체가 실제로 데이터를 가지고 있는것이 아님을 알 수 있겠네요.. 그럼 얕은 복사를 알았으면, 깊은 복사를 해봐야겠죠?? ㅎㅎ아닌가.. 아무튼 위와같이 참조하는 방식이 아닌 복사를 구현하기위해서는 직접 복사생성자를 구현해야 하겠습니다. 

#include<iostream>

#include<string>

using namespace std;

 

class A{

private:

    char *name;

    char *phone;

    int age;

public:

    A(char *_name, char* _phone, int _age){

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

        strcpy(name,_name);

        phone = new char[strlen(_phone)+1];

        strcpy(phone,_phone);

        age = _age;

    }

    A(const A& Obj){

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

        strcpy(name,Obj.name);

        // private 접근가능하니 const 해둡시다

        phone = new char[strlen(Obj.phone)+1];

        strcpy(phone,Obj.phone);

       

        age = Obj.age;

    }

    void output(){

        cout<<name<<endl;

        cout<<phone<<endl;

        cout<<age<<endl;

    }

    void modify(char *val){

        strcpy(name,val);

    }

    ~A(){

        delete []name;

        delete []phone;

    }

};

 

int main(){

    A *a = new A("Hahahia","010-7549-2870",21);

    A b(*a);

    a->output();

    delete a;

    b.output();

}





 ㅎㅎ 참 쉽네영.. 이크 내번호 ㅋ



'Language > C++' 카테고리의 다른 글

Template Function(템플릿 함수)  (0) 2012.09.01
C++ 상속(inheritance)  (0) 2012.09.01
C++ 포함  (0) 2012.09.01
Operator Overloading(연산자 오버로딩)  (0) 2012.09.01
1주차  (0) 2011.06.27
Comments