복사
되어 전달되는 방식 #include <iostream>
using namespace std;
void swap(int a, int b){
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main() {
int m = 2, n = 9;
swap(m,n);
cout << m << ' ' << n;
실행 결과
2 9
(1) 매개변수 a,b가 swap() 함수의 스택에 생성
(2) m,n 값이 a,b에 복사
(3) a와 b의 값이 교환
(4) swap() 함수 종료하면 swap() 스택과 함께 a,b도 사라짐
(5) 하지만 main() 스택에 m,n은 변함없이 2,9의 값 유지
포인터 타입
의 매개변수에 전달받는 방식#include <iostream>
using namespace std;
void swap(int *a, int *b){
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
int m = 2, n = 9;
swap(&m,&n);
cout << m << ' ' << n;
실행 결과
9 2
(1) 포인터 매개변수 a,b가 swap()의 스택에 생성
(2) m,n의 주소가 a,b에 전달(포인터 a,b는 m,n을 각각 가리킴)
(3) 포인터 a,b가 가리키는 값이 교환되면
(4) 그 결과 m,n의 값이 교환
(5) swap() 함수가 종료하면 a,b가 사라지고 main() 스택의 m,n은 서로 교환된 채 남음
C++에서는 함수에 객체를 전달할 수 있으며, 기본 타입의 값을 전달하는 것과는 약간 다름
#include <iostream>
using namespace std;
class Circle {
private:
int radius;
public:
Circle();
Circle(int r);
~Circle();
double getArea() { return 3.14*radius*radius; }
int getRadius() { return radius; }
void setRadius(int radius) { this->radius = radius; }
};
Circle::Circle() {
radius = 1;
cout << "생성자 실행 radius = " << radius << endl;
}
Circle::Circle(int radius) {
this->radius = radius;
cout << "생성자 실행 radius = " << radius << endl;
}
Circle::~Circle() {
cout << "소멸자 실행 radius = " << radius << endl;
}
void increase(Circle c) {
int r = c.getRadius();
c.setRadius(r+1);
}
int main() {
Circle waffle(30);
increase(waffle);
cout << waffle.getRadius() << endl;
}
실행 결과
생성자 실행 radius = 30 // waffle 생성
소멸자 실행 radius = 31 // c 소멸 (c의 생성자 실행되지 않았음)
30
소멸자 실행 radius = 30 // waffle 소멸
📌 함수 안에서 매개 변수 객체에 어떤 변화가 일어나도 실인자(원본 객체)를 훼손시키지 않음
✅ 값에 의한 호출 시 객체 복사 시간
실인자 객체의 크기가 크면 객체를 복사하는 시간이 커지는 단점 존재
비대칭 구조
실행실행결과
생성자 실행 radius = 30 // waffle 생성
소멸자 실행 radius = 31 // c 소멸 (c의 생성자 실행되지 않았음)
30
소멸자 실행 radius = 30 // waffle 소멸
#include <iostream>
using namespace std;
class Circle {
private:
int radius;
public:
Circle();
Circle(int r);
~Circle();
double getArea() { return 3.14*radius*radius; }
int getRadius() { return radius; }
void setRadius(int radius) { this->radius = radius; }
};
Circle::Circle() {
radius = 1;
cout << "생성자 실행 radius = " << radius << endl;
}
Circle::Circle(int radius) {
this->radius = radius;
cout << "생성자 실행 radius = " << radius << endl;
}
Circle::~Circle() {
cout << "소멸자 실행 radius = " << radius << endl;
}
void increase(Circle *p) {
int r = p->getRadius();
p->setRadius(r+1);
}
int main() {
Circle waffle(30);
increase(&waffle); // waffle 객체의 주소를 전달함
cout << waffle.getRadius() << endl;
}
실행결과
생성자 실행 radius = 30 // waffle 생성
30
소멸자 실행 radius = 30 // waffle 소멸
Circle c1(5);
Circle c2(30);
c1 = c2;
#include <iostream>
using namespace std;
class Circle {
int radius;
public:
Circle() { radius = 1; }
Circle(int radius) { this->radius = radius; }
void setRadius(int radius) { this->radius = radius; }
double getArea() { return 3.14*radius*radius; }
};
Circle getCircle() {
Circle tmp(30);
return tmp; // 객체 tmp을 리턴한다.
}
int main() {
Circle c; // 객체가 생성된다. radius=1로 초기화된다.
cout << c.getArea() << endl;
c = getCircle();
cout << c.getArea() << endl;
}
실행결과
3.14
2826
Circle 클래스의 객체를 리턴하는 getCircle() 함수
(1) return 문이 실행되면 tmp의 복사본 생성
(2) 이 복사본이 getCircle()을 호출한 곳으로 전달
(3) tmp 소멸
c = getCircle();cout << c.getArea() << endl;
- 객체 c가 생성될 때 반지름 값이 1이었지만, getCircle()이 리턴한 tmp 객체로 치환되면 객체 c의 반지름은 30이 됨
- c는 tmp(30)과 내용물이 같아짐
참조
: 가리킨다는 뜻으로, 참조변수(reference variable)는 이미 선언된 변수에 대한 별명(alias)이다.참조 변수
int n = 2;
int &refn = n; // 참조 변수 refn 선언, refn은 n에 대한 별명, refn과 n은 동일한 변수
refn = 3; // n의 값도 3으로 변경됨
Circle circle;
Circle &refc = circle; // 참조 변수 refc 선언, refc는 circle에 대한 별명, refc와 circle은 동일한 변수
refc.setRadius(30); // refc가 참조하는 circle 객체의 radius 멤버 변수가 30으로 변경
// refc->setRadius(30);으로는 불가능(포인터가 아니라서)
int n = 2;
int &refn = n;
refn = 3;
n = 5; // n = 5, refn = 5가 됨
refn++; // n = 6, refn = 6이 됨
int n = 2;
int &refn = n;
int *p = &refn; // p는 refn의 주소를 가짐, p는 n의 주소
*p = 20; // n = 20, refn = 20;
int n = 2;
int &refn2; // refn2가 어떤 변수에 대한 참조인지 초기화되지 않았음
int &refn2;
int & refn2;
int& refn2;
char &n[10]; // 컴파일 오류
int &r = refn; // 참조 변수 refn에 대한 참조 변수 r 선언 가능
✅ *(Asterisk) 연산자의 기능
1. 방금 배운 참조자 기능
2. 두 개의 변수, 혹은 상수 사이에 위치하게 되면 비트연산(AND) 기능
3. 변수의 메모리 주소를 나타내는 기능
#include <iostream>
using namespace std;
class Circle {
int radius;
public:
Circle() { radius = 1; }
Circle(int radius) { this->radius = radius; }
void setRadius(int radius) { this->radius = radius; }
double getArea() { return 3.14*radius*radius; }
};
int main() {
Circle circle;
Circle &refc = circle;
refc.setRadius(10);
cout << refc.getArea() << " " << circle.getArea(); // 두 호출은 동일 객체에 대한 호출
}
실행결과
314 314
참조에 의한 호출
(call by reference) : 함수의 매개 변수를 참조 타입으로 선언하여, 매개 변수가 함수를 호출하는 쪽의 실인자를 참조(reference)하여 실인자와 공간을 공유하도록 하는 인자 전달 방식참조 매개 변수
(reference parameter) : 참조 타입으로 선언된 매개 변수#include <iostream>
using namespace std;
void swap(int &a, int &b) {
int tmp;
tmp = a;
a = b;
b = tmp;
}
int main() {
int m=2, n=9;
swap(m, n); // 참조에 의한 호출
cout << m << ' ' << n;
}
실행 결과
9 2
int average(int a[], int size) {
if(size <= 0) return 0; // size는 음수가 될 수 없음
int sum = 0;
for(int i=0; i<size; i++) sum += a[i];
return sum/size;
}
위 함수를 아래와 같이 호출하면
int x[] = {1,2,3,4};
int avg = average(x, -1); //avg에 0이 리턴됨
average()의 리턴값이 0인 경우, 계산된 평균이 0인지, 잘못된 매개 변수를 알리기 위한 0인지 알 수 없음
따라서 아래와 같이 average() 함수 수정
#include <iostream>
using namespace std;
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;
}
참조 리턴
: 변수 등과 같이 현존하는 공간에 대한 참조의 리턴char c = 'a';
char& fine() { // char 타입의 참조 리턴
return c; // 변수 c에 대한 참조 리턴
}
char a = find(); // a = 'a'
char& ref = find(); // ref는 c에 대한 참조
ref = 'M'; // c = 'M'
find() = 'b'; // c = 'b'
char a = find();
char& ref = find();
ref = 'M'; // c = 'M'
해당 포스팅은 '황기태, 『명품 C++ Programming』, 생능출판사'를 참고하여 작성하였습니다.