Hoon222y

[1218-4] 기본 생성자 , 멤버 이니셜라이저, 복사 생성자의 종류 본문

코딩/교육

[1218-4] 기본 생성자 , 멤버 이니셜라이저, 복사 생성자의 종류

hoon222y 2018. 12. 18. 21:48
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//기본 생성자
#include <iostream>
using namespace std;
class Point{
    int _x, _y;
    //사용자가 생성자를 추가하지 않으면 컴파일러가 생성자를 자동으로 추가하는데
    //이를 기본생성자(default constructor)라고 한다.
public:
    //만약 사용자가 생성자를 추가한다면 컴파일러는 기본 생성자를 추가하지 않는다.
    //이는 초기화되지 않은 객체 사용으로 인하여 프로그램이 불안정해지는것을 막기 위해서이다.
    //즉 아래에서 인자 2개짜리 하고 Point(){}를 없애면 main 문에서 Point p1은 에러가 발생한다.
    //원래는 따로 생성자를 안해도 Point p1은 오류 안남.
    Point(){}
    Point(int x, int y){
        _x = x;
        _y = y;
    }
};
int main(){
    Point p1;        //인자가 없는 생성자를 사용하여 객체를 생성하는 코드
    Point p2(12);  //인자가 2인 생성자를 사용하여 객체를 생성하는 코드
}
cs




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#if 0
//멤버 이니셜라이져
#include <iostream>
using namespace std;
 
class Circle{
    int _x, _y;
    int _radius;
    const double PI;
 
public:
    //맴버 이니셜라이저 : 맴버를 초기화 하고 싶다면 사용한다.
    //시용방법은 생성자() : 멤버(값), 멤버2(값) , ...
    Circle() : PI(3.14) {
        //생성자 내부에서 맴버에 대하여 값을 대입하는 값을 설정하는 것은
        //초기화가 아니라 대입니다.
        _x = _y = _radius = 0;
    }
};
 
int main(){
    Circle c; //sizeof(Circle)의 크기만큼 메모리를 할당한다음 생성자를 사용하여 메모리에 값을 대입
}
cs




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
#include <iostream>
using namespace std;
class Point{
    int _x , _y;
public:
    Point(int x, int y){
        _x = x;
        _y = y;
    }
};
//멤버 이니셜라이저를 반드시 사용해야 하는경우
//1. const 를 선언한 변수
//2. 레퍼런스 변수 - 레퍼런스 변수는 선언과 동시에 반드시 초기화가 되어야 하기 때문ㅇ
//3. 기본 생성자가 없는 멤버 데이터가 존재하는 경우
 
class Circle{
    Point p;
    int _radius;
    const double PI;
public:
    //Circle() : PI(3.14), p(0,0){
    //    _radius = 0;
    //}
    //위처럼 하거나 아래처럼 하거나
    Circle(int x, int y , int r) : PI(3.14), p(x, y), _radius(r){}
};
 
int main(){
    Circle c;
}
cs



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
//사용저의 이름과 나이를 저장하는 클래스를 생각해 봅시다.
#include <iostream>
using namespace std;
class Person{
    char *name;
    int age;\
public:
    //Person(const char* n, int a) : age(a){
    //    strcpy(name, n);
    //}
    Person(string s, int a) : age(a){
        name = new char[s.length()];
    }
    void print(){
        cout << name << " " << age << endl;
    }
};
 
 
//연습문제 : (-> 위의 클래스를 동적할당 하는 코드로 변경하라)
int main(){
    Person p("hoon"25);
    Person q = p;
    p.print();
    q.print();
}
cs

라고 나는 했는데 


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
#if 0
//사용저의 이름과 나이를 저장하는 클래스를 생각해 봅시다.
#include <iostream>
using namespace std;
class Person{
    char *name;
    int age;
public:
    //Person(const char* n, int a) : age(a){
    //    strcpy(name, n);
    //}
    Person(const char * n, int a) : age(a){
        name = new char[strlen(n)+1];
        strcpy(name, n);
    }
    ~Person(){
        delete[] name;
    }
    void print(){
        cout << name << " " << age << endl;
    }
};
 
//연습문제 : (-> 위의 클래스를 동적할당 하는 코드로 변경하라)
int main(){
    Person p("hoon"25);
    Person q = p;
    p.print();
    q.print();
}
cs

이렇게 하는데 strlen(n)+1 만큼 크기를 잡는데 1은 개행문자 1개이다. 


기본 복사 생성자

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
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
class Person{
    char *name;
    int age;
public:
    Person(const char * n, int a) : age(a){
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }
    ~Person(){
        delete[] name;
    }
    void print(){
        cout << name << " " << age << endl;
    }
    //자신의 타입을 인자로 하는 생성자를 복사 생성자라고 한다.
    //이는 객체의 복사를 지원하기 위해 사용되는 생성자
    //사용자가 복사 생성자를 정의하지 않는경우 , 컴파일러가 이를 자동으로 추가하는데
    //이를 기본 복사 생성자라고 한다.
    //기본 복사 생성자의 복사 정책은 얕은 복사이다.
    Person(const Person& o) : name(o.name), age(o.age) {}
    
    //이건 깊은 복사인가? 아닌가?
    //Person(const Person& o): name(o.name) , age(o.age) {
    //    name = new char[strlen(o.name) + 1];
    //    strcpy(name, o.name);
    //   age = o.age;
    //}
 
};
int main(){
    Person p("hoon"25);
    Person q = p;  // Person q(p)
    p.print();
    q.print();
}
cs



깊은 복사 생성자

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
31
32
33
#include <iostream>
using namespace std;
class Person{
    char *name;
    int age;
public:
    Person(const char * n, int a) : age(a){
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }
    ~Person(){
        delete[] name;
    }
    void print(){
        cout << name << " " << age << endl;
    }
    //깊은 복사 정책의 복사 생성자
    //깊은 복사 얕은 복사 , 참조 계수는 그림 참고 할 것
    // 값은 단순 복사하고 동적 할당된 메모리만 깊은 복사를 수행 한다.
    Person(const Person& o) {
        name = new char[strlen(o.name) + 1];
        strcpy(name, o.name);
        age = o.age;
    }
};
//만약 객체 내부에서 동적 할당 된 자원이 있다면 반드시
// 소멸자와 복사 생성자를 정의해야 한다.
int main(){
    Person p("hoon"25);
    Person q = p;  // Person q(p)
    p.print();
    q.print();
}
cs


참조 계수 방식 복사 생성자

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
31
32
33
34
35
#include <iostream>
using namespace std;
class Person{
    char *name;
    int age;
    int *ref;
    
public:
    Person(const char * n, int a) : age(a), ref(new int (1)){
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }
    //참조 계수 방식의 소멸자
    ~Person(){
        if (--(*ref) == 0){
            delete[] name;
            delete ref;
        }
    }
    void print(){
        cout << name << " " << age << endl;
    }
    //참조 계수 방식 복사 생성자
    //모드 값을 얕은 복사 후, 참조 계수만 증분한다. 꼭 알둬라
    Person(const Person& o) : name(o.name) , age(o.age) , ref (o.ref) {
        ref++;
    }
};
 
int main(){
    Person p("hoon"25);
    Person q = p;  // Person q(p)
    p.print();
    q.print();
}
cs



복사 금지 정책


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
 
#include <iostream>
using namespace std;
 
class Person{
    char *name;
    int age;
    
    //복사 금지 정책을 사용하기 위해서는
    // Person q = p 같은 코드를 error 내기 위해서는
    // 복사 생성자를 private 영역에 정의하면 된다.
    Person(const Person& o) : name(o.name), age(o.age) {
    }
    
public:
    Person(const char * n, int a) : age(a){
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }
    ~Person(){delete[] name;}
    void print(){    cout << name << " " << age << endl;}
};
int main(){
    Person p("hoon"25);
    Person q = p;
    
    p.print();
    q.print();
}
 
cs





+) 연습문제

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
31
32
33
34
35
36
37
38
39
40
41
42
43
//연습문제 아래의 동작을 수행하는 클래스를 구현하라
#include <iostream>
using namespace std;
class String {
private:
    char *name;
    size_t len;
    int *ref;
public:
    String(const char * n, int a) : ref(new int(1)){
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }
    String(const char * n){
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }
    ~String(){
        if (--(*ref) == 0){
            delete[] name;
            delete ref;
        }
    }
    String(const String& o): name(o.name), ref(o.ref){
        ++*ref;
    }
    char* to_str(){
        return name;
    }
};
 
int main(){
    String s1 = "hello";            //String s1("hello")
    String s2 = s1;                    //String s2(s1)
    
    cout << s1.to_str() << endl;
    cout << s2.to_str() << endl;
    
    //주의할 점 : 반드시 프로세스는 정상종료 해야되며
    //복사 정책은 참조 계수 방식으로
    
}
 
cs


Comments