C++ 함수와 참조, 복사 생성자
2025년 09월 18일 09시
카테고리 -
LECTURE,
객체지향프로그래밍II
객체지향프로그래밍II(김정준) 3주차 강의내용
함수의 인자 전달 방식
- 값에 의한 호출, call by value
함수가 호출되면 매개 변수가 스택에 생성됨
호출하는 코드에서 값을 넘겨줌
호출하는 코드에서 넘어온 값이 매개 변수에 복사됨
- 주소에 의한 호출, call by address
함수의 매개 변수는 포인터 타입
함수가 호출되면 포인터 타입의 매개 변수가 스택에 생성됨
호출하는 코드에서는 명시적으로 주소를 넘겨줌
기본 타입 변수나 객체의 경우, 주소 전달
배열의 경우, 배열의 이름
호출하는 코드에서 넘어온 주소 값이 매개 변수에 저장됨
‘값에 의한 호출’로 객체 전달
- 함수를 호출하는 쪽에서 객체 전달
객체 이름만 사용
- 함수의 매개 변수 객체 생성
매개 변수 객체의 공간이 스택에 할당
호출하는 쪽의 객체가 매개 변수 객체에 그대로 복사됨
매개 변수 객체의 생성자는 호출되지 않음
- 함수 종료
매개 변수 객체의 소멸자 호출
매개 변수 객체의 생성자 소멸자의 비대칭 실행 구조
- 값에 의한 호출 시 매개 변수 객체의 생성자가 실행되지 않는 이
유?
호출되는 순간의 실인자 객체 상태를 매개 변수 객체에 그대로 전달하기 위함
함수에 객체 전달 – ‘주소에 의한 호출’로
- 함수 호출시 객체의 주소만 전달
함수의 매개 변수는 객체에 대한 포인터 변수로 선언
함수 호출 시 생성자 소멸자가 실행되지 않는 구조
객체 치환 및 객체 리턴
- 객체 치환
동일한 클래스 타입의 객체끼리 치환 가능
객체의 모든 데이터가 비트 단위로 복사
치환된 두 객체는 현재 내용물만 같을 뿐 독립적인 공간 유지
Circle c1(5);
Circle c2(30);
c1 = c2; // c2 객체를 c1 객체에 비트 단위 복사. c1의 반지름 30됨
Circle getCircle() {
Circle tmp(30);
return tmp; // 객체 tmp 리턴
}
Circle c; // c의 반지름 1
c = getCircle(); // tmp 객체의 복사본이 c에 치환. c의 반지름은 30이 됨
참조
가리킨다는 뜻으로, 이미 존재하는 객체나 변수에 대한 별명
포인터와 혼용됨
참조 변수 선언
- 참조자 &의 도입
- 이미 존재하는 변수에 대한 다른 이름(별명)을 선언
참조 변수는 이름만 생기며
참조 변수에 새로운 공간을 할당하지 않는다.
초기화로 지정된 기존 변수를 공유한다
int n = 2;
int &refn = n; // 참조 변수 refn 선언. refn은 n에 대한 별명
Circle circle;
Circle &refc = circle; // 참조 변수 refc 선언. refc는 circle에 대한 별명
참조에 의한 호출
- 참조를 가장 많이 활용하는 사례
- call by reference라고 부름
- 함수 형식
- 함수의 매개 변수를 참조 타입으로 선언
참조 매개 변수(reference parameter)라고 부름
참조 매개 변수는 실인자 변수를 참조함
참조매개 변수의 이름만 생기고 공간이 생기지 않음
참조 매개 변수는 실인자 변수 공간 공유
참조 매개 변수에 대한 조작은 실인자 변수 조작 효과
포인터와의 내부 기능적 차이

참조 매개변수가 필요한 사례
다음 코드에 어떤 문제가 있을까?

- average() 함수의 작동
계산에 오류가 있으면 0 리턴, 아니면 평균 리턴
- 만일 average()가 리턴한 값이 0이라면?
평균이 0인 거야? 아니면 오류가 발생한 거야?
- 아래 예제에서 해결
bool average(int a[], int size, int& avg) {
if(size <= 0)
return false;
int sum = 0;
for(int i=0; i<size; i++)
sum += a[i];
avg = sum/size;
return true;
}
int main() {
int x[] = {0,1,2,3,4,5};
int avg;
if(average(x, 6, avg)) cout << "평균은 " << avg << endl;
else cout << "매개 변수 오류" << endl;
if(average(x, -2, avg)) cout << "평균은 " << avg << endl;
else cout << "매개 변수 오류 " << endl;
}
참조 리턴
- C 언어의 함수 리턴
- 함수는 반드시 값만 리턴
기본 타입 값 : int, char, double 등
포인터 값
- C++의 함수 리턴
- 함수는 값 외에 참조 리턴 가능
- 참조 리턴
변수 등과 같이 현존하는 공간에 대한 참조 리턴
변수의 값을 리턴하는 것이 아님
char c = 'a';
char& find() { // char 타입의 참조 리턴
return c; // 변수 c에 대한 참조 리턴
}
char a = find(); // a = 'a'가 됨
char &ref = find(); // ref는 c에 대한 참조
ref = 'M'; // c= 'M'
find() = 'b'; // c = 'b'가 됨
C++에서 얕은 복사와 깊은 복사
- 얕은 복사(shallow copy)
- 객체 복사 시, 객체의 멤버를 1:1로 복사 - 객체의 멤버 변수에 동적 메모리가 할당된 경우
사본은 원본 객체가 할당 받은 메모리를 공유하는 문제 발생
- 깊은 복사(deep copy)
- 객체 복사 시, 객체의 멤버를 1:1대로 복사 - 객체의 멤버 변수에 동적 메모리가 할당된 경우
사본은 원본이 가진 메모리 크기 만큼 별도로 동적 할당
원본의 동적 메모리에 있는 내용을 사본에 복사 - 완전한 형태의 복사
사본과 원본은 메모리를 공유하는 문제 없음(공유가 항상 문제인 것은 아님)

복사 생성자
- 복사 생성자(copy constructor)란?
- 특징
- 한 클래스에 오직 한 개만 선언 가능
- 복사 생성자는 보통 생성자와 클래스 내에 중복 선언 가능
- 모양
클래스에 대한 참조 매개 변수를 가지는 독특한 생성자
- 복사 생성자 선언
class Circle {
............
Circle(const Circle& c); // 복사 생성자 선언
............
};
Circle::Circle(const Circle& c) { // 복사 생성자 구현
............
}

디폴트 복사 생성자
- 복사 생성자가 선언되어 있지 않는 클래스
- 디폴트 복사 생성자의 정의
Circle::Circle(const Circle& c) {
this->radius = c.radius;
// 원본 객체 c의 각 멤버를 사본(this)에 복사한다.
}
얕은 복사 생성자가 오류를 발생시키는 사례
- 클래스 내에서 동적으로 메모리를 할당하는 경우
복사할 객체에서도 따로 동적으로 메모리를 할당해야 하며
이를 위해 깊은 복사생성자에서 따로 지정해야 함