티스토리 뷰
1.함수의 인자 전달방법과 차이점
(1) 값에 의한 호출(call by value)
–함수가 호출되면 매개 변수가 스택에 생성된다.
–호출하는 코드에서 '값'을 넘겨준다.
–호출하는 코드에서 넘어온 값이 매개 변수에 '복사'된다.
–
(2) 주소에 의한 호출(call by address)
- 함수의 매개 변수는 포인터 타입으로 선언
- 함수가 호출되면 포인터 타입의 매개 변수가 스택에 생성된다.
- 호출하는 코드에서 넘어온 '주소' 값이 매개 변수에 저장된다.
(3) 참조에 의한 호출(call by reference)
- 참조 변수는 이미 선언된 변수에 대한 별명이다.
- 참조자(&)를 이용하여 선언하며, 선언 시 반드시 원본 변수로 초기화를 하여야 한다.
- 참조 변수 선언은 이름만 생성하는 것이다. 별도의 참조 변수를 위한 공간은 할당 되지 않는다.
- 대신에 원본 변수의 공간을 공유 한다.
*참조 변수 사용 형식
int n = 2;
int &refn = n;
Circle circle;
Circle &redfc = circle;
*참조 변수 사용 시 주의사항
- 반드시 초기화를 해주어야 한다.
- 참조자(&)는 자료형 타입과 변수 이름 사이의 어느 위치에 있어도 무관하다.
- 참조 변수 배열을 만들 수 없다.
- 참조 변수에 대한 변수 선언이 가능하다.
*참조 변수 사용 장점
- 참조 매개 변수를 사용하면 간단히 변수를 넘겨주기만 하면 된다.
- 함수 내에서 보통변수처럼 사용 하기 때문에 작성이 쉽고 가독성도 좋다.
2.값에 의한 호출의 문제점과 주소에 의한 호출의 비교 예제(소스코드, 실행결과에 대한 설명)
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 |
#include <cstdlib>
#include <iostream>
using namespace std;
//객체배열 생성, 소멸 예제
class Circle {
int radius;
public:
Circle();
Circle(int r);
~Circle();
void setRadius(int r) { radius = r; }
int getRadius(){return radius;}
double getArea() { return 3.14*radius*radius; }
};
Circle::Circle() {
radius = 1;
cout << "생성자 실행 radius = " << radius << endl;
}
Circle::Circle(int r) {
radius = r;
cout << "생성자 실행 radius = " << radius << endl;
}
Circle::~Circle() {
cout << "소멸자 실행 radius = " << radius << endl;
system("PAUSE");
}
void increase(Circle c){ //이 함수 내에서 외부와는 독립적으로 값을 변경. 함수 내에서 값만 바뀐다.
int r = c.getRadius();
c.setRadius(r+1);
}
void increase2(Circle *c){ //주소값을 넘겨 받았기 때문에 main함수에서 생성된 waffle객체의 값이 변경된다.
int r = c->getRadius();
c->setRadius(r+1);
}
int main(int argc, char *argv[])
{
//값에 의한 호출
Circle waffle(30);
increase(waffle);//값을 넘겨 1 증가.
cout << waffle.getRadius() << endl;//30으로 출력된다.
//주소에 의한 호출
increase2(&waffle);//주소를 넘겨 1 증가.
cout << waffle.getRadius() << endl;//31 로 출력된다.
system("PAUSE");
return EXIT_SUCCESS;
} |
cs |
<실행 결과>
3. 참조매개변수의 활용 예(소스코드, 실행결과에 대한 설명)
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 |
#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))//변수 avg를 함수의 참조 매개 변수에 넘긴다.
cout << "평균은 " << avg << endl;//같은 공간을 공유 하기 때문에 avg에 값이 할당된다.
else
cout << "매개 변수 오류" << endl;
if (average(x, -2, avg))//size가 0보다 작기 때문에 false가 리턴되었다.
cout << "평균은 " << avg << endl;
else
cout << "매개 변수 오류" << endl;
} |
cs |
<실행 결과>
4. 객체의 복사과정
*복사 생성자(객체복사)
- 객체의 복사 생성시 호출되는 특별한 생성자이다.
- 한 클래스에 오직 한 개만 선언 가능하다.
- 복사 생성자는 보통 생성자와 클래스 내에 중복 선언 가능하다.
- 클래스에 대한 참조 매개 변수를 가지는 생성자이다.
- 복사 생성자가 선언되어 않았는데 생성문을 사용한 경우 묵시적으로 디폴트 복사 생성자를 삽입한다.
*사용 형식
Circle src(30);
Circle dest(src);
*복사 생성자 형식
Circle :: Circle(Cricle &c){
this->radius = c.radius;
}
복사 과정은 얕은 복사와 깊은 복사 두가지로 나뉜다.
*얕은 복사
- 원본의 포인터만 복사해서 실행한다. 즉 메모리 주소를 공유한다.
- 컴파일러가 삽입하는 디폴트 복사생성자가 얕은 복사이다.
- 컴파일러가 삽입하는 디폴트 복사생성자는 원본 객체의 사본(this)에 일대일로 복사된다.
- 메모리 주소를 공유하기 때문에 하나를 바꾸면 다른 하나도 바뀐다.
*깊은 복사
- 포인터 뿐만 아니라 원본 객체의 모든 내용까지 가져간다.
- 즉 메모리 주소까지 복사하기 떄문에 서로 독립적으로 실행된다.
- 깊은 복사를 위해서 복사생성자를 구현 할 때, 복사객체의 멤버를 위한 공간을 따로 할당한다.
*깊은 복사 예제
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 |
#include<iostream>
#include<cstring>
using namespace std;
class Person {
char* name;
int id;
public :
Person(int id, char* name);
Person(Person& person);
~Person();
void changeName(char* name);
void show() { cout << id << ',' << name << endl; }
};
Person::Person(int id, char* name) {//보통 생성자
this->id = id;
int len = strlen(name);
this->name = new char[len + 1];
strcpy(this->name, name);
}
Person::Person(Person& person) {//복사 생성자, 깊은 복사를 한다.
this->id = person.id;//id 값 복사
int len = strlen(person.name);//name의 문자 갯수 할당
this->name = new char[len + 1];//name 공간 할당.
strcpy(this->name, person.name);//name 복사
cout << "복사 생성자 실행. 원본 객체의 이름" << this->name << endl;
}
Person :: ~Person() {
if (name)
delete[] name;
}
void Person::changeName(char* name) {
if (strlen(name) > strlen(this->name))//현재 이름보다 긴 이름으로 변경 불가
return;
strcpy(this->name, name);
}
int main() {
Person father(1, "kitae");//보통 생성자로 객체 생성
Person dauther(father);//복사 생성자로 father 객체를 복사 생성
cout << "dauther 객체 생성 직후 ----" << endl;
father.show();
dauther.show();
dauther.changeName("Grace");//dauther 객체의 이름을 grace로 변경.
cout << "dauther 이름을 Grace라고 변경 한 후 -----" << endl;
father.show();
dauther.show();
return 0;
} |
cs |
<실행 결과>
*복사 과정
보통 객체 생성(father) → 얕은 복사(메모리 주소 공유되게 구현) → 복사 객체 생성(dauther)
→ 깊은 복사(메모리 주소까지 복사되게 구현)
'객체 지향 프로그래밍 > 이론 정리' 카테고리의 다른 글
[C++]함수 중복, 추상클래스 (0) | 2017.11.15 |
---|---|
[C++]함수 중복과 static (0) | 2017.11.08 |
[C++]this 포인터, string 클래스 (0) | 2017.10.18 |
[C++]객체 포인터, 객체 배열,동적 메모리 할당 (0) | 2017.10.11 |
[C++]접근지정자, 인라인 함수, 구조체, 파일분리 (0) | 2017.09.27 |
- Total
- Today
- Yesterday
- 파이썬 예제
- 백준
- 파이썬 터틀
- 백준 10451
- 버츄어박스
- 파이썬 함수
- 파이썬 while
- 자료구조
- 자바 에센셜 실습문제
- 파이썬 단계적 개선
- css 그리드
- 파이썬 문자열
- 파이썬 연산자
- 자바스크립트 그래프
- 파이썬
- 파이썬 객체
- 파이썬 선택문
- 파이썬 진수 변환
- 자바스크립트 자료구조
- 파이썬 for
- 백준 11501
- 파이썬 클래스
- css 박스
- 파이썬 if문
- css
- 웹
- 자바
- 백준 1874
- 명품 c++ 실습
- 파이썬 리스트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |