jam 블로그

[C++] 005. 복사 생성자 본문

개발 및 관련 자료/C

[C++] 005. 복사 생성자

kid1412 2013. 5. 12. 20:05
728x90

I. C,C++ 스타일 초기화

  • C 에서의 스타일 초기화

    • int val = 10;
  • C++에서의 스타일 초기화

    • int val(10); or int val = 10;

II. 복사 생성자의 형태

  1. #include <iostream>
    using namespace std;
  2. class AAA
    {
    public:
     AAA()
     {
      cout<<"AAA() 호출"<<endl;
     }
     AAA(int i)
     {
      cout<<"AAA(int i) 호출"<<endl;
     }
     AAA(const AAA& a)
     {
      cout<<"AAA(const AAA& a) 호출"<<endl;
     }
    };
  3. int main()
    {
     AAA obj1;
     AAA obj2(10);
     AAA obj3(obj2);
     return 0;
    }
  •  위의 소스에 main안에 보면 AAA obj3(obj2); 이것이 복사 생성자이다. 복사 생성자를 선언 할 경우 &는 꼭 선언을 해줘야 한다.

III. 디폴트 복사 생성자

  •  디폴트 복사 생성자 형태

    • Point(const Point &p) 이런 식을 들어간다.
  1.  #include <iostream>
  2. using namespace std;
  3. class Point
    {
     int x,y;
    public:
     Point(int _x,int _y)
     {
      x = _x;
      y = _y;
     }
     /*
     Point(const Point &p)
     {
      x = p.x;
      y = p.y;
     }*/ //디폴트 복사 생성자
     void ShowData()
     {
      cout<<x<<' '<<y<<endl;
     }
    };
  4. int main()
    {
     Point p1(10,20);
     Point p2(p1);
  5.  p1.ShowData();
     p2.ShowData();
    }
  • 디폴트 복사 생성자는 맴버 변수 대 멤버 변수의 복사를 수행한다.

IV. 깊은 복사를 하는 복사 생성자

  • 디폴트 복사 생성자의 문제점
  1.  #include <iostream>
  2. using namespace std;
  3. class Person
    {
     char *name;
     char *phone;
     int age;
    public:
     Person(char* _name, char* _phone,int _age);
     ~Person();
     void ShowData();
    };
  4. Person::Person(char* _name, char* _phone,int _age)
    {
     name = new char[strlen(_name)+1];
     strcpy(name,_name);
  5.  phone = new char[strlen(_phone)+1];
     strcpy(phone,_phone);
  6.  age = _age;
    }
  7. Person::~Person()
    {
     delete []name;
     delete []phone;
    }
  8. void Person::ShowData()
    {
     cout<<"name : "<<name<<endl;
     cout<<"phone: "<<phone<<endl;
     cout<<"age : "<<age<<endl;
    }
  9. int main()
    {
     Person p1("KIM","123-123",23);
     Person p2 = p1;
     return 0;
    }
  • 위의 소스를 실행 시켜보면 오류가 나게 된다 그 이유는 얕은 복사를 하고 있기 때문이다.

15.jpg 

  • 위의 그림이 얕은 복사이다. 위쪽의 소스가 위의 그림 처럼 되어 있는데 오류 나는 이유는 잘 실행되다가 소멸 과정(소멸은 생성이 나중에 된것 부터 소멸된다.)에서 p2가 사라지면 가리키는 값은 메모리에서 해제 되고  p1도 소멸할 때 메모리를 해제하려고보니 해제할 메모리 공간이 없어서 오류가 발생하게 되는 것 이다.

    • 디폴트 복사 생성자는 얕은 복사를 하므로, 깊은 복사를 하도록 직접 복사 생성자를 제공해야 하낟.

 

  • 깊은 복사
  1. #include<iostream>
  2. using namespace std;
  3. class Person
    {
     char *name;
     char *phone;
     int age;
    public:
     Person(char* _name, char* _phone,int _age);
     Person(const Person& p);
     ~Person();
     void ShowData();
    };
  4. Person::Person(const Person &p)
    {
     name = new char[strlen(p.name)+1];
     strcpy(name,p.name);
  5.  phone = new char[strlen(p.phone)+1];
     strcpy(phone,p.phone);
     age = p.age;
    }
  6. Person::Person(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;
    }
    Person::~Person()
    {
     delete []name;
     delete []phone;
    }
  7. void Person::ShowData()
    {
     cout<<"name : "<<name<<endl;
     cout<<"phone : "<<phone<<endl;
     cout<<"age : "<<age<<endl;
  8. }
  9. int main()
    {
     Person p1 ("kim","123-123",23);
     Person p2 = p1;
  10.  p1.ShowData();
     p2.ShowData();
    }
  •   위의 소스가 깊은 복사를 한 것이다. 명시적으로 복사 생성자를 만들었다.

V. 복사 생성자가 호출되는 시점

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

    • 기존에 생성된 객체로 새로운 객체를 초기화 하는 경우
    • 함수 호출 시 객체를 값에 의해 전달하는 경우
    • 함수 내에서 객체를 값에 의해 리턴하는 경우
  1.  #include <iostream>
    using namespace std;
  2. class AAA
    {
    public:
     AAA()
     {
      cout<<"AAA() 호출"<<endl;
     }
     AAA(const AAA& a)
     {
      cout<<"AAA(const AAA& a) 호출"<<endl;
     }
    };
  3. int main()
    {
     AAA obj1;
     AAA obj2 = obj1;
     return 0;
    }
  • 위의 소스는 호출되는 시점에서 첫번째인 기존에 생성된 객체로 새로운 객체를 초기화하는 경우이다.

    • obj1은 기존에 이미 생성된 객체이고 obj2는 새롭게 생성하고자 하는 객체이다.
  1.  void function(int a){}
    int main()
    {
     int n =10;
     function(n);
    }
  • 위의 같은 소느는 n을 10으로 초기화 하고나서 function으로 변수 n을 인자로 전달 할때 매개변수 a가 이 값을 복사하게 된다.

    • Call-By-Value에 의한 함수 호출 과정을 세분화 하면

      • 매개 변수를 위한 메모리 공간 할당
      • 전달 인자 값의 복사
  1.  #include <iostream>
    using namespace std;
  2. class AAA
    {
     int val;
    public:
     AAA(int i)
     {
      val = i;
     }
     AAA(const AAA& a)
     {
      cout<<"AAA(const AAA& a)호출"<<endl;
      val =a.val;
     }
     void ShowData()
     {
      cout<<"val : "<<val<<endl;
     }
    };
    void funcion(AAA a)
    {
     a.ShowData();
    }
    int main()
    {
     AAA obj(30);
     funcion(obj);
     return 0;
    }
  • 위의 소스를 보면 function(obj)를 보면 obj가 가지고 있는 값을 a에 복사하는 것이다.

    • 매개변수로 생성되는 객체의 복사 생성자가 호출되는 것이다.
  1.  #include <iostream>
    using namespace std;
  2. class AAA
    {
     int val;
    public:
     AAA(int i)
     {
      val = i;
     }
     AAA(const AAA& a)
     {
      cout<<"AAA(const AAA& a)호출"<<endl;
      val =a.val;
     }
     void ShowData()
     {
      cout<<"val : "<<val<<endl;
     }
    };
    AAA function(void)
    {
     AAA a(10);
     return a;
    }
    int main()
    {
     function();
     return 0;
    }
  •  위의 소스는 main에서 function 함수를 호출 하고나서 function 함수 안에서 AAA a객체를 생성하고 나서 return a로 a객체 복사본을 리턴한다.

문제

5 -1

문제1

연습문제 4 -1의 3번 문제를 통해서 NameCard클래스를 정의하였다. 이 클래스도 생성자 내에서 메모리 공간을 동적 할당하고 있으며, 소멸자에서 이를 해제하고 있기 때문에 깊은 복사를 하는 복사 생성자가 필요한 상황이다. 이에 적절한 복사 생성자를 정의해 보기 바란다.

'개발 및 관련 자료 > C' 카테고리의 다른 글

[C++] 007. 상속(Inheritance)의 이해  (0) 2013.05.12
[C++] 006. static 멤버와 const 멤버  (0) 2013.05.12
[C++] 004. 클래스의 완성  (0) 2013.05.12
[C++] 003. 클래스의 기본  (0) 2013.05.12
[C++] 002. C기반의 C++ 2  (0) 2013.05.12
Comments