728x90
객체 치환 및 객체 리턴
[ 객체 치환 ]
- 연산자를 이용하여 새로운 객체에 원본 객체를 대입하는 대입문이라고 생각하면 이해하기 쉬움.
- 동일한 클래스 타입의 객체끼리 치환 가능
- 객체의 모든 데이터가 비트 단위로 복사
- 치환된 두 객체는 현재 내용물만 같을 뿐, 독립적인 공간을 유지
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 a = 10; // 변수
int* p = &a; // 포인터 변수
int &ref = a; // 참조 변수.
// 참조는 메모리 변수에 이미 변수 a가 있어야 사용 가능
cout << a << endl; // 출력값 : 10
cout << *p << endl; // 출력값 : 10
cout << ref << endl; // 출력값 : 10
[ 참조 변수 선언 및 사용 사례 ]
int n = 2;
int &ref = n; // 참조 변수 refn 선언. refn은 n에 대한 별명
ref = 3;
Circle circle;
Circle &refc = circle; // 참조 변수 refc 선언. refc는 circle에 대한 설명
refc.setRadius(30);
예제 실습
{ 예제 5-3 기본 타입 변수에 대한 참조 }
#include <iostream>
using namespace std;
int main() {
cout << "i" << '\t' << "n" << '\t' << "refn" << endl;
int i = 1;
int n = 2;
int& refn = n; // 참조 변수 refn 선언. refn은 n에 대한 설명
n = 4;
refn++; // refn=5, n=5
cout << i << '\t' << n << '\t' << refn << endl;
refn = i; // refn=1, n=1
refn++; // refn=2, n=2
cout << i << 'wt' << n << '\t' << refn << endl;
// int *p = &refn 과 int *p = &n 모두 가능
int* p = &refn; // p는 n의 주소를 가짐
*p = 20; // refn=20, n=20
cout << i << '\t' << refn << endl;
}
여기서 몇 가지 중요한 부분을 살펴보자 먼저 [ int* p = &refn; ] 이 부분을 보면 주석에도 작성해 놓은 것 처럼 [ int* p = &n ] 으로도 작성 가능하다. 그 이유는 참조 변수 refn이 바로 변수 n을 가르키기 때문이다. 또한, 참조에 대한 포인터 변수 선언시에 등호를 기준으로 오른쪽에 &가 있을 경우 주소를 나타내고 등호 기준 왼쪽에 &가 있을 경우 참조 변수를 나타낸다.
{ 예제 5-4 객체에 대한 참조 }
#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; // circle 객체에 대한 참조 변수 refc 선언
refc.setRadius(10);
cout << refc.getArea() << " " << circle.getArea();
}
// 코드 실행 결과 : 314 314
참조에 의한 호출
[ 참조에 의한 호출 ]
- 참조를 가장 많이 활용하는 사례
- call by reference 라고 부름
- 함수 형식 : 함수의 매개 변수를 참조 타입으로 선언
- 참조 매개 변수(reference parameter)라고 부름 ▶ 참조 매개 변수는 실인자 변수를 참조함
- 참조 매개 변수의 이름만 생기고 공간이 생기지 않음
- 참조 매개 변수는 실인자 변수 공간 공유
- 참조 매개 변수에 대한 조작은 실인자 변수 조작 효과
[ 참조에 의한 호출 사례 ]
[ 참조 매개변수가 필요한 사례 ]
위 코드에서 무슨 문제가 있을까? average() 함수는 계산에 오류가 있으면 0을 리턴, 아니면 평균을 리턴하는 방식으로 작동한다. 만약 average()가 리턴한 값이 0이라면 평균이 0인지 오류가 발생한건지 헷갈리게 된다. 따라서 위와 같은 상황을 방지하고자 참조 매개변수가 필요하다.
{ 참조 매개 변수로 평균을 리턴하는 올바른 코드 }
#include <iostream>
using namespace std;
bool average(int a[], int size, int& avg) { // 참조 매개 변수 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;
// avg에 평균이 넘어오고, average()는 true 리턴
if (average(x, 6, avg)) cout << "평균은" << avg << endl;
else cout << "매개 변수 오류" << endl;
// avg의 값은 의미없고, average()는 false 리턴
if (average(x, -2, avg)) cout << "평균은" << avg << endl;
else cout << "매개 변수 오류" << endl;
}
예제 실습
{ 예제 5-6 참조에 의한 호출로 Circle 객체에 참조 전달 }
#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;
}
// 참조 매개 변수 c 사용
void increaseCircle (Circle &c) {
int r = c.getRadius();
c.setRadius(r+1);
}
int main() {
Circle waffle(30);
increaseCircle(waffle); // 참조에 의한 호출
cout << waffle.getRadius() << endl;
}
// 출력 결과
// 생성자 실행 radius = 30 >> waffle 객체 생성
// 31
// 소멸자 실행 = radius = 31 >> waffle 객체 소멸
Vector 실습
[ vector 컨테이너 ]
- 가변 길이 배열을 구현한 제네릭 클래스 : 개발자가 백터의 길이에 대한 고민 필요없음
- 원소의 저장, 삭제, 검색 등 다양한 벡멤버 함수 지원
- 벡터의 저장된 원소는 인덱스로 접근 가능 : 인덱스는 0부터 시작
[ vector 클래스의 주요 멤버와 연산자 ]
- push_back(element) : 벡터의 마지막에 element 추가
- at(int index) : index 위치의 원소에 대한 참조 리턴
- begin() : 벡터의 첫 번째 원소에 대한 참조 리턴
- empty() : 벡터가 비어 있으면 true 리턴
- end() : 벡터의 끝(마지막 원소 다음)을 가리키는 참조 리턴
- erase(iterator it) : 벡터에서 it가 가르키는 원소 삭제, 삭제 후 자동으로 벡터 조절
- insert(iterator it, elemet) : 벡터 내 it 위치에 element 삽입
- size() : 벡터에 들어있는 원소의 개수 리턴
- operator[]() : 지정된 원소에 대한 참조 리턴
- operator=() : 이 벡터를 다른 벡터에 치환(복사)
[ 문자열을 저장하는 벡터 만들기 연습 ]
string 타입의 벡터를 이용하여 문자열을 저장하는 벡터를 만들고, 5개의 이름을 입력받아 사전에서 가장 뒤에 나오는 이름을 출력하라.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> sv; // 문자열 벡터 생성
string name;
cout << "이름을 5개 입력하라" << endl;
for(int i =0; i <5; i ++) { // 한 줄에 한 개씩 5 개의 이름을 입력받는다
cout << i+1 << " << ";
getline(cin, name);
sv.push_back(name);
}
name = sv.at(0); // 벡터의 첫 원소
for(int i =1; i<sv.size(); i ++) {
if(name < sv[i]) // sv[i]의 문자열이 name 보다 사전에서 뒤에 나옴
name = sv[i]; // name 을 sv[i]의 문자열로 변경
}
cout << "사전에서 가장 뒤에 나오는 이름은 " << name << endl;
}
728x90
'Programming > C++' 카테고리의 다른 글
[C++ 스터디] 템플릿과 표준 템플릿 라이브러리{STL}_(2) (0) | 2022.12.08 |
---|---|
[C++ 스터디] 템플릿과 표준 템플릿 라이브러리{STL}_(1) (0) | 2022.12.04 |
[C++ 스터디] 상속(1) (1) | 2022.11.27 |
[C++ 스터디] static 멤버 (0) | 2022.11.20 |
[C++ 스터디] 참조리턴 / 복사 생성자 / 함수 중복 (0) | 2022.11.13 |