5.1 함수의 인자 전달 방식 리뷰
- 값에 의한 호출 : 호출하는 코드에서 넘겨주는 실인자 값이 함수의 매개 변수에 복사되어 전달
- 주소에 의한 호출 : 주소를 직접 포인터 타입의 매개 변수에 전달 받음
값에 의한 호출로 swap 사용
- m,n 값에 변화가 존재하지 않음
#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;
}
주소에 의한 호출로 swap 함수 호출
- m과 n 값이 변경됨
#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;
}
5.2 함수 호출시 객체 전달
값에 의한 호출 과정
- 값에 의한 호출 과정은 매개 변수를 직접 복사하므로 increase(waffle) 값은 waffle 값을 복사하여 별개의 스택에 저장하고, 함수가 종료하면 객체가 소멸한다. 즉 waffle 변수 자체의 값은 변하지 않는다.
void increase(Circle c){
int r = c.getRadius();
c.setRadius(r+1);
}
int main(){
Circle waffle(30);
increase(waffle); // 값에 의한 호출 과정
cout << waffle.getRadius() << "\n";
// 30 출력
}
문제점 : 객체를 매개변수로 가지는 함수의 경우 생성자는 실행되지 않고 소멸자만 실행되도록 컴파일 하기 때문에 비대칭 구조가 일어난다
주소에 의한 호출로 객체를 전달하면 이 문제점을 해결할 수 있다.
원본 객체를 복사하는 시간 소모가 없지만, 원본을 잃어버릴 수 있으므로 유의해야한다
void increase(Circle *p){
int r = p->getRadius();
c->setRadius(r+1);
}
int main(){
Circle waffle(30);
increase(&waffle); // 주소에 의한 호출
cout << waffle.getRadius() << "\n";
// 31 출력
}
5.3 객체 치환 및 객체 리턴
객체 치환 시 객체의 모든 데이터가 비트 단위로 복사된다
동일한 클래스 타입에 대해서만 적용된다
Circle c1(5);
Circle c2(30);
c1=c2; //c2 객체를 c1객체에 비트 단위로 복사한다
함수의 객체 리턴
Circle getCircle(){
Circle tmp(30);
return tmp; //객체 tmp 리턴
}
int main(){
Circle c; // c의 반지름은 1
c= getCircle(); //tmp 객체의 복사본이 c에 치환됨. c의 반지름이 30
}
5.4 참조와 함수
참조 변수를 선언하기 위해 & 기호를 사용하고 이를 참조자라고 부른다
참조란 이미 선언된 변수에 대한 별명이다
선언 시 반드시 원본 변수로 초기화하여야 한다
참조 변수의 배열을 만들 수 없다.
int n=2;
int &refn = n; //참조 변수 refn 선언, refn은 n에 대한 별명. refn과 n은 동일한 변수
Circle circle;
Circle &refc = circle; //참조 변수 refc 선언, refc은 circle에 대한 별명. refc와 circle은 동일한 변수
//refn과 refc는 따로 변수 공간을 가지지 않고 각각 n과 circle을 공유한다
//포인터 생성도 가능
int *p = &refn; //p는 refn의 주소를 가짐
*p = n; //n=20, p=20
참조에 의한 호출
- 함수의 매개 변수를 참조 타입으로 선언하여 매개 변수가 함수를 호출하는 쪽의 실인자를 참조하여 실인자와 공간을 공유하게 함
#include <iostream>
using namespace std;
void swap (int &a, int &b){
int tmp;
tmp = a;
a = b;
b = tmp;
} //참조 매개 변수 a와 b는 이름만 존재하고 공간을 할당받지 않는다
int main (void){
int m=2, n=9;
swap(m,n);
cout << m << ", " << n ;
}
참조 매개 변수가 필요한 경우
#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 (void){
int x[] = {0,1,2,3,4,5};
int avg;
if(average(x, 6, avg)) cout<<"평균은 " << avg << "\n";
else cout<<"error\n";
if(average(x, -2, avg)) cout<<"평균은 " << avg << "\n";
else cout<<"error\n";
}
값에 의한 호출로 값을 매개 변수에 전달하면 두 가지 사항에 유의해야 한다
- 함수 내에서 매개 변수 객체를 변경해도 원본 객체를 변경시키지 않는다
- 매개 변수 객체의 생성자가 실행되지 않고 소멸자만 실행되는 비대칭 구조로 작동
그에 반해 참조에 의한 호출은?
- 참조 매개 변수로 이루어진 모든 연산은 원본 객체에 대한 연산이 된다
- 참조 매개 변수는 이름만 생성되므로 생성자와 소멸자는 아예 실행되지 않는다
예제 5-6)
#include <iostream>
using namespace std;
class Circle{
int radius;
public:
Circle(){
radius = 1;
cout << "생성자 실행 radius = " << radius << "\n";
}
~Circle(){
cout << "소멸자 실행 radius = " << radius << "\n";
};
Circle(int radius){
this->radius=radius;
cout << "생성자 실행 radius = " << radius << "\n";
};
double getArea() {return 3.14*radius*radius;}
int getRadius() {return radius;}
void setRadius(int radius){
this->radius=radius;
}
};
void increase(Circle &c){
int r = c.getRadius();
c.setRadius(r+1);
}
int main (void){
Circle waffle(30);
increase(waffle);
cout << waffle.getRadius() << "\n";
}
예제 5-7)
#include <iostream>
using namespace std;
class Circle{
int radius;
public:
Circle(){
radius = 1;
}
Circle(int radius){
this->radius=radius;
};
double getArea() {return 3.14*radius*radius;}
int getRadius() {return radius;}
void setRadius(int radius){
this->radius=radius;
}
};
void readRadius(Circle &c){
int r;
cout << "정수 값으로 반지름을 입력하세요>>";
cin >> r;
c.setRadius(r);
}
int main (void){
Circle donut;
readRadius(donut);
cout << "donut의 면적 = "<<donut.getArea() << "\n";
}
참조 리턴
함수가 참조를 리턴할 수 있다
char c = 'a';
char& find(){
return c; //변수 c에 대한 참조 리턴
}
char a = find(); // a = 'a'
char &ref = find(); //ref는 c에 대한 참조
ref = 'M'; // c = 'M'
find() = 'b'; //c = 'b' 가 됨
예제 5-8)
#include <iostream>
using namespace std;
char& find(char s[], int index){
return s[index];
}
int main(){
char name[] = "MIKE";
cout << name << "\n";
find(name,0) = 'S'; //SIKE
cout << name << "\n";
char &ref = find(name,2); //ref = 'K'
ref = 'T'; //SITE
cout << name << "\n";
}
5.5 복사생성자
얕은 복사 : 충돌 발생 할 수 있음. 포인터가 복사되었기 때문에 메모리를 공유함. 가능하면 일어나지 않게 할 것
깊은 복사 : 포인터의 메모리도 복사함
복사 방법
복사 생성자 선언
- 복사 생성자의 매개 변수는 오작 하나, 자기 클래스에 대한 참조, 클래스에 오직 한 개만 선언할 수 있다
class ClassName {
ClassName (const ClassName &c); //복사 생성자
}
복사 생성자 실행
Circle (const Circle& c){
this->radius = c.radius;
}
Circle src(30);
Circle dest(stc);
예제 5-9)
#include <iostream>
using namespace std;
class Circle{
int radius;
public:
Circle(const Circle& c){
this->radius = c.radius;
cout << "복사 생성자 실행 radius = " << radius << "\n";
};
Circle(){radius=1;}
Circle(int radius){
this->radius=radius;
}
double getArea() {
return 3.14*radius*radius;
}
};
int main(){
Circle src(30);
Circle dest(src);
cout << "원본의 면적 = " << src.getArea() << "\n";
cout << "사본의 면적 = " << dest.getArea() << "\n";
}
복사 생성자 가지지 않았을 때 : 디폴트 복사 생성자를 묵시적으로 삽입하고 이 생성자를 호출하도록 컴파일 함
: 얕은 복사를 실행함
예제 5-11)
#include <iostream>
#include <cstring>
using namespace std;
class Person{
char* name;
int id;
public:
Person(int id, const char* name){
this->id=id;
int len = strlen(name);
this->name=new char[len+1];
strcpy(this->name, name);
};
Person(const Person& person){
this->id=person.id;
int len = strlen(person.name);
this->name = new char [len+1];
strcpy(this->name, person.name);
cout << "복사 생성자 실행. 원본 객체의 이름" << this->name << "\n";}
~Person(){
if(name)
delete [] name;
};
void changeName(const char *name){
if (strlen(name)>strlen(this->name))
return;
strcpy(this->name, name);
}
void show(){
cout << id << "," << name << "\n";
}
};
int main(){
Person father(1,"kitae");
Person daughter(father);
cout << "daughter 생성 직후 " << "\n";
father.show();
daughter.show();
daughter.changeName("Grace");
cout << "daughter 이름을 Grace로 변경한 후 " << "\n";
father.show();
daughter.show();
}
묵시적 복사 생성
1. 객체로 초기화 하여 객체가 생성될 때
2. 값에 의한 호출로 객체가 전달될 때
3. 함수가 객체를 리턴할 때
실습 문제
1
#include <iostream>
using namespace std;
class Circle{
int radius;
public:
Circle() {radius=1;}
Circle(int r) { this->radius = r; }
void show(){
cout << "반지름 : " << radius<<"\n";
}
};
void swap(Circle &first, Circle &second){
Circle tmp;
tmp=first;
first=second;
second=tmp;
}
int main(){
Circle a(1), b(3);
a.show();
b.show();
swap(a,b);
a.show();
b.show();
}
2
#include <iostream>
using namespace std;
void half(double &n){
n = n/2;
}
int main(){
double n = 20;
half(n);
cout << n;
}
3
#include <iostream>
using namespace std;
void combine(string &one, string &two, string &three){
three = one+' '+two;
}
int main(){
string text1("i love you"), text2("very much");
string text3;
combine(text1, text2, text3);
cout << text3;
}
4
#include <iostream>
using namespace std;
bool bigger(int a, int b, int &big){
if (a==b){
big = a;
return true;
}else{
if(a > b) big = a;
else big = b;
return false;
}
}
int main(){
int a, b, big;
cout << "두 개의 정수를 입력하세요";
cin >> a >> b;
if (bigger(a, b, big)) {
cout << "두 수는 같습니다" << endl;
} else {
cout << a << "와 " << b << "중 큰 수는 " << big << "입니다." << endl;
}
}
5
#include <iostream>
using namespace std;
class Circle{
int radius;
public:
Circle(int r) { radius=r;}
int getRadius(){return radius;}
void setRadius(int r){radius=r;}
void show(){
cout << "반지름이 " << radius << "인 원" << "\n";
}
};
void increaseBy(Circle &a, Circle &b){
int r = a.getRadius() + b.getRadius();
a.setRadius(r);
}
int main(){
Circle x(10), y(5);
increaseBy(x, y);
x.show();
}
6
#include <iostream>
#include <string>
using namespace std;
char& find(char a[], char c, bool& success) {
for (int i = 0; i < strlen(a); i++) {
if (a[i] == c) {
success = true;
return a[i];
}
}
success = false;
}
int main() {
char s[] = "Mike";
bool b = false;
char& loc = find(s, 'M', b);
if (b == false) {
cout << "M을 발견할 수 없다" << endl;
return 0;
}
loc = 'm';
cout << s << endl;
return 0;
}
7
#include <iostream>
#include <string>
using namespace std;
class MyIntStack {
int p[10];
int tos;
public:
MyIntStack(){
tos = -1;
};
bool push(int n){
if (tos >= 9) return false;
p[++tos] = n;
return true;
};
bool pop(int& n){
if (tos < 0) return false;
n = p[tos--];
return true;
};
};
int main() {
MyIntStack a;
for (int i = 0; i < 11; i++) {
if (a.push(i)) cout << i << ' ';
else cout << endl << i + 1 << " 번째 stack full" << endl;
}
int n;
for (int i = 0; i < 11; i++) {
if (a.pop(n)) cout << n << ' ';
else cout << endl << i + 1 << " 번째 stack empty";
}
cout << endl;
}
8
#include <iostream>
#include <string>
using namespace std;
class MyIntStack {
int *p;
int size;
int tos;
public:
MyIntStack() :MyIntStack(1) {}
MyIntStack(int size){
this->p = new int[size];
this->size = size;
this->tos = -1;
}
MyIntStack(MyIntStack& s){
int len=s.size;
this->p = new int[len];
this->size=len;
this->tos = s.tos;
for (int i=0;i<tos;i++){
this->p[i] = s.p[i];
}
}
bool push(int n){
if (tos>=9) return false;
p[++tos] = n;
return true;
}
bool pop(int& n){
if (tos < 0) return false;
n = p[tos--];
return true;
}
~MyIntStack(){
delete []p;
}
};
int main() {
MyIntStack a(10);
a.push(10);
a.push(20);
MyIntStack b = a;
b.push(30);
int n;
a.pop(n);
cout << "스택 a에서 팝한 값 " << n << endl;
b.pop(n);
cout << "스택 b에서 팝한 값 " << n << endl;
}
9
#include <iostream>
using namespace std;
class Accumulator {
int value;
public:
Accumulator(int value){
this->value=value;
};
Accumulator& add(int n){
value += n;
return *this;
};
int get(){
return value;
};
};
int main() {
Accumulator acc(10);
acc.add(5).add(6).add(7);
cout << acc.get();
}
10
#include <iostream>
using namespace std;
class Buffer {
string text;
public:
Buffer(string text) { this->text = text; }
void add(string next) { text += next; }
void print() { cout << text << endl; }
};
Buffer &append (Buffer& buf, string text){
buf.add(text);
return buf;
}
int main() {
Buffer buf("Hello");
Buffer& temp = append(buf, "Guys");
temp.print();
buf.print();
return 0;
}
11
(1) char
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Book {
char* title;
int price;
public:
Book(const char* title, int price){
int len = strlen(title);
this->title = new char[len + 1];
strcpy(this->title, title);
this->price = price;
}
Book(Book& b){
int len = strlen(b.title);
this->title = new char [len+1];
strcpy(this->title, b.title);
this->price = b.price;
}
~Book(){
if (this->title)
delete[]title;
}
void set(const char* title, int price) {
if (this->title) delete[] this->title; // 할당된 메모리가 있다면 반환한후
int len = strlen(title);
this->title = new char[len + 1]; // 새로운 메모리 다시 할당
strcpy(this->title, title);
this->price = price;
}
void show() { cout << title << ' ' << price << "원" << endl; }
};
int main() {
Book cpp("명품C++", 10000);
Book java = cpp;
java.set("명품자바", 12000);
cpp.show();
java.show();
}
(2)string
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Book {
string title;
int price;
public:
Book(string title, int price){
this->title = title;
this->price=price;
}
void set(string title, int price) {
this->title = title;
this->price = price;
}
void show() { cout << title << ' ' << price << "원" << endl; }
};
int main() {
Book cpp("명품C++", 10000);
Book java = cpp;
java.set("명품자바", 12000);
cpp.show();
java.show();
}
12
(1)
#include <iostream>
#include <string>
using namespace std;
class Dept {
int size;
int* scores;
public:
Dept(int size) {
this->size = size;
scores = new int[size];
}
Dept(const Dept& dept){
this->size = dept.size;
this->scores = new int[dept.size];
for (int i = 0;i < this->size;i++)
scores[i] = dept.scores[i];
}
~Dept() {
if (this->scores) {
delete[]scores;
}
}
int getSize() {
return this->size;
}
void read() {
cout << size << "개 정수 입력 >> ";
for (int i = 0;i < size;i++)
cin >> scores[i];
}
bool isOver60(int index) {
if (this->scores[index] > 60) {
return true;
}
else {
return false;
}
}
};
int countPass(Dept dept) {
int count = 0;
for (int i = 0;i < dept.getSize();i++)
if (dept.isOver60(i)) count++;
return count;
}
int main() {
Dept com(10);
com.read();
int n = countPass(com);
cout << "60점 이상은 " << n << "명" << endl;
}
(3)
include <iostream>
#include <string>
using namespace std;
class Dept {
int size;
int* scores;
public:
Dept(int size) {
this->size = size;
scores = new int[size];
}
~Dept() {
if (this->scores) {
delete[]scores;
}
}
int getSize() {
return this->size;
}
void read() {
cout << size << "개 정수 입력 >> ";
for (int i = 0;i < size;i++)
cin >> scores[i];
}
bool isOver60(int index) {
if (this->scores[index] > 60) {
return true;
}
else{
return false;
}
}
};
int countPass(Dept &dept) {
int count = 0;
for (int i = 0;i < dept.getSize();i++)
if (dept.isOver60(i)) count++;
return count;
}
int main() {
Dept com(10);
com.read();
int n = countPass(com);
cout << "60점 이상은 " << n << "명" << endl;
}
'명품 C++' 카테고리의 다른 글
[명품 C++] 7. 프렌드와 연산자 중복 (0) | 2023.01.06 |
---|---|
[명품 C++] 6. 함수 중복과 static 멤버 (0) | 2023.01.04 |
[명품 C++] 4. 객체 포인터와 객체 배열, 객체의 동적 생성 (0) | 2022.12.30 |
[명품 C++] 3. 클래스와 객체 (0) | 2022.12.27 |
[명품 C++] 2.C++ 프로그래밍의 기본 (0) | 2022.12.26 |