• 참조와 함수

참조변수(reference variable) : 이미 선언된 변수에 대한 별명(alias)


& 를 이용하여 선언하며, 선언시 반드시 원본 변수로 초기화 해야한다.


아래의 코드에서 refn은 n을 참조하며, refc는 circle을 참조한다.

refn과 refc는 따로 변수 공간을 가지지 않고, n과 circle을 공유한다.

참조변수는 일반변수와 사용법이 동일하며, 참조변수 사용은 원본 변수의 사용과 같다.

참조변수는 포인터가 아니므로 주의하자.

1
2
3
4
5
6
7
8
9
int n=2;
int &refn = n;
refn=3;    // n == refn == 3
n=5;    // n == refn == 5
 
Circle circle;
Circle &refc = circle;
refc.setRadius(30);
//refc->setRadius(30);으로 하면 안된다.
cs


참조 변수 선언시 주의사항이 있는데,


첫번째, 초기화를 바로 해줘야한다. 그렇지 않으면 오류가 발생한다.

두번째, 포인터처럼 참조자 &의 위치에 무관하다. 단 데이터 타입 뒤, 참조변수 앞에 와야한다.

세번째, 참조 변수의 배열을 만들 수는 없다.

네번째, 참조 변수를 또다른 참조 변수로 참조할 수 있다.

다섰째, 참조 변수는 숫자로 초기화 할 수 없다.


그렇다면 여기서 Call by reference를 살펴보자.

m과 n을 참조 매개변수로 받아, 참조 변수를 매개변수처럼 사용하고 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
using namespace std;
 
void swap(int &a, int &b){
    int temp=a;
    a=b;
    b=temp;
}
int main(){
    int m=2, n=9;
    swap(m, n);
    cout<<m<<' '<<n<<endl;
    return 0;
}
cs

출력값

9 2


바뀌어 나온다.



그럼 참조에 의한 호출의 장점은 무엇일까?

포인터를 사용하는경우는 코드 짜기도 힘들고, 가독성도 떨어진다.

하지만 참조 변수를 사용하면, 변수를 넘겨주기만 하면 되고, 작성하기 쉽고 보기도 편하다.



  • 복사 생성자

복사에는 Shallow copy와 Deep copy가 있다.


Shallow copy는 그저 같은 내용을 가리키는것이다.

Deep copy는 내용까지 복사해 원본과 완전히 똑같게 복사하는 것이다.


Shallow copy의 문제점은 원본과 사본이 같은 데이터를 가리키고 있기 때문에,

데이터를 바꾸면 원본, 사본이 모두 바뀐다는것이다.


C++에는 특별한 복사 생성자(copy constructor)가 있다.

copy constructor는 다음과 같이 선언한다.

1
2
3
class ClassName{
    ClassName(ClassName &c);
};
cs


copy constructor의 매개 변수는 오직 하나이며, 자기 클래스에 대한 차모로 선언된다.

또한copy constructor는 클래스에 오직 한개만 선언할 수 있다.

1
2
3
4
5
6
7
8
9
class Circle{
    ...
    Circle(Circle &c);    //copy constructor 선언
    ...
};
 
Circle::Circle(Circle &c){    //copy constructor 구현
    this->radius = c.radius;
}
cs


실행은 다음과 같이 할 수 있다.

1
2
Circle src(30);    //보통 생성자 호출
Circle dest(src);    //src 객체를 복사하여 dest 객체 생성.copy constructor 호출.
cs


copy constructor를 선언하지 않아도, 디폴트 copy constructor가 있어서 에러는 나지 않는다.



Shallow copy를 사용해서 프로그램이 비정상 종료되는 경우를 살펴보자

메모리를 공유하고있기 때문에 father의 name과 daughter의 name이 같이 바뀌었다.

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
44
45
46
47
48
#include <iostream>
#include <cstring>
 
using namespace std;
 
class Person{ //Person 클래스 선언 
    char* name;
    int id;
public:
    Person(int id, const char* name); //생성자 
    ~Person(); //소멸자 
    void changeName(const char* name);
    void show(){ cout<< id << ',' << name << endl; }
};
 
Person::Person(int id, const char* name){ //생성자 
    this->id = id;
    int len = strlen(name); //name의 문자 개수 
    this->name = new char [len+1]; //name 문자열 공간 동적할당 
    strcpy(this->name, name); //name에 문자열 복사 
}
Person::~Person(){ //소멸자 
    if(name) //name에 동적 할당된 배열이 있으면 
        delete [] name;    //메모리 반환 
}
 
void Person::changeName(const char* name){ //이름변경 
    if(strlen(name) > strlen(this->name))
        return//현재 name에 할당된 메모리보다 긴 이름으로 바꿀 수 없다. 
    strcpy(this->name, name);
}
 
int main(){
    Person father(1"Kitae");
    Person daughter(father);
    
    cout<<"daughter 객체 생성 직후 ---"<<endl;
    
    father.show();
    daughter.show();
    
    daughter.changeName("Grace");
    cout<<"daughter 이름을 Grace로 변경한 후---"<<endl;
    father.show();
    daughter.show();
    
    return 0
}
cs



Deep copy를 사용해서 코드를 변경시켜보자.

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
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <cstring>
 
using namespace std;
 
class Person{ //Person 클래스 선언 
    char* name;
    int id;
public:
    Person(int id, const char* name); //생성자 
    Person(Person &person);
    ~Person(); //소멸자 
    void changeName(const char* name);
    void show(){ cout<< id << ',' << name << endl; }
};
 
Person::Person(int id, const char* name){ //생성자 
    this->id = id;
    int len = strlen(name); //name의 문자 개수 
    this->name = new char [len+1]; //name 문자열 공간 동적할당 
    strcpy(this->name, name); //name에 문자열 복사 
}
Person::Person(Person &person){
    this->id = person.id;
    int len = strlen(person.name);
    this->name = new char [len+1];
    strcpy(this->name, person.name);
    cout<<"copy constructor. name : "<<this->name<<endl
}
Person::~Person(){ //소멸자 
    if(name) //name에 동적 할당된 배열이 있으면 
        delete [] name;    //메모리 반환 
}
 
void Person::changeName(const char* name){ //이름변경 
    if(strlen(name) > strlen(this->name))
        return//현재 name에 할당된 메모리보다 긴 이름으로 바꿀 수 없다. 
    strcpy(this->name, name);
}
 
int main(){
    Person father(1"Kitae");
    Person daughter(father);
    
    cout<<"daughter 객체 생성 직후 ---"<<endl;
    
    father.show();
    daughter.show();
    
    daughter.changeName("Grace");
    cout<<"daughter 이름을 Grace로 변경한 후---"<<endl;
    father.show();
    daughter.show();
    
    return 0;
}
cs








Posted by Jyoel :