C++ 4주차 생성자와 소멸자
소멸자
의미
객체가 소멸될 때 자동으로 호출되는 함수
특징
임의로 호출이 불가능함
2개 이상 존재할 수 없음(다형성이 불가능함)
객체가 사라질 때, 할당받은 메모리의 해제, 파일 저장 및 닫기, 네트워크 닫기 등의 작업을 함
클래스 이름앞에 ~을 붙여 사용
예시
1 2 3 4 5
class Circle{ Circle(); ~Circle(); } Circle::~Circle();
리턴 타입이 없음
선언이 안되어 있을 경우, 기본 소멸자가 자동 생성됨
생성자, 소멸자의 실행 순서
객체 생성 위치에 따른 분류
지역 객체
- 함수 내에 선언된 객체, 함수가 종료될 때 소멸됨
전역 객체
- 함수 외부에 선언된 객체, 프로그램이 종료될 때 소멸됨
객체 생성 순서
- 전역 객체 : 프로그램에 선언된 순서로 생성됨
- 지역 객체 : 함수가 호출되는 순간에 순서대로 생성
객체 소멸 순서
- 함수 종료 시, 지역 객체가 생성 순서의 역 순으로 소멸됨
- 프로그램 종료 시, 전역 객체가 생성 순서의 역 순으로 소멸됨
new 키워드로 동적으로 생성된 객체
- new를 실행하는 순간에 객체가 생성됨
- delete 연산자가 실행되는 순간에 객체가 소멸됨
예시 코드
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
class Circle {
public:
int radius;
Circle();
Circle(int r);
~Circle(); //소멸자
double getArea();
};
Circle::Circle() {
radius = 5;
cout << "지름이 " << radius * 2 << "인 원 생성" << endl;
}
Circle::Circle(int r) {
radius = r;
cout << "지름이 " << r * 2 << "인 원 생성" << endl;
}
Circle::~Circle() {
cout << "지름이 " << radius * 2 << "인 원 소멸" << endl;
}
double Circle::getArea() {
return 3.14 * radius * radius;
}
Circle globalDonut(1000);
Circle globalPizza(2000);
void func() {
Circle fDonut(100);
Circle fPizza(200);
}
int main(){
Circle mainCircle1;
Circle mainCircle2(10);
func();
}
결과
1
2
3
4
5
6
7
8
9
10
11
12
지름이 2000인 원 생성
지름이 4000인 원 생성
지름이 10인 원 생성
지름이 20인 원 생성
지름이 200인 원 생성
지름이 400인 원 생성
지름이 400인 원 소멸
지름이 200인 원 소멸
지름이 20인 원 소멸
지름이 10인 원 소멸
지름이 4000인 원 소멸
지름이 2000인 원 소멸
예시 코드에서의 실행 순서
- 프로그램 로딩 - globalDonut, globalPizza 객체 생성
- main 함수 실행 - mainCircle1, mainCircle2 객체 생성
- func 함수 실행 - fDonut, fPizza 객체 생성
- func 함수 종료 - fDonut, fPizza 객체 소멸
- main 함수 종료 - mainCircle1, mainCircle2 객체 소멸
- 프로그램 종료 - globalDonut, globalPizza 객체 소멸
접근 지정자
종류
- public - 외부 함수에서 접근이 가능함
- private(기본값) - 동일 클래스 멤버 함수만 접근 가능함
- protected - 자신과 상속받은 클래스에서만 접근 가능함
특징
- 객체의 캡슐화를 지원함
- 멤버에 대한 접근 권한을 지정함
인라인 함수
함수 호출과정의 문제점 :
빈번한 호출은 불필요한 오버헤드 문제를 일으킴
스택에 레지스터 저장 -> 함수 호출 및 실행 -> 스택에 저장된 레지스터 복구 -> 함수 복귀
레지스터 - 리턴주소, 지역변수 값, 매개변수
사용방법
inline 키워드 사용
전처리기에서 컴파일 과정에서 자동으로 코드에 삽입됨
예시 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
inline int divide(int x) { return (x/2); } int main() { int sum = 0; for(int i=1; i<=3; i++) { if(divide(i)) //(x/2) 호출 { cout << i << " 호출 " << endl; sum += i; } } cout << "----" << endl; cout << sum; }
결과
1 2 3 4
2 호출 3 호출 ---- 5
장점
- 자주 호출되는 함수의 오버헤드를 줄임 -> 성능 향상
단점
- 실행 프로그램의 크기 증가로 인한 메모리 오버헤드
자동 인라인 함수
inline 키워드 사용 없이도, 컴파일러가 인라인을 처리하는 함수
예시)
1 2 3 4 5 6 7 8
class Circle{ private: int radius; public: Circle() { radius = 1; } //자동 인라인 함수 Circle(int r); double getArea() { return 3.14 * radius * radius; } };
구조체
특징
- 클래스와 유사(상속, 멤버, 접근 지정자)
- 기본 접근지정자는 public
- C언어와 호환됨
사용방법
1
2
3
4
5
struct 구조체명{
타입 멤버변수1;
...
타입 멤버변수n;
}
예시 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Circle {
private:
int radius;
public:
Circle(int r) { radius = r; } //구조체의 생성자
double getArea();
};
double Circle::getArea() {
return 3.14 * radius * radius;
}
int main(){
Circle donut(5);
cout << "면적은 " << donut.getArea();
}
결과
1
면적은 78.5
파일 분리
사용 이유
클래스 선언과 구현을 분리함
선언 / 구현을 분리
- 클래스 재사용 및 수정에 효율적
- 클래스 선언부는 헤더파일에서 관리함
- 클래스 구현부는 CPP 파일에서 관리함
프로젝트 관리에 효율적
- 개발 업무 분할에 직관
- 클래스 단위의 세부화 된 코드를 관리
- 공동 작업을 할 때 변경점에 대한 영향을 최소화 함
외부 파일 사용하는 방법
#include “파일명.h”
헤더 중복으로 인한 문제
헤더 중복 선언으로 인한 문제는 아래와 같이 전처리기 지시문을 사용하여 해결이 가능함
1
2
#ifndef 헤더명
#define 헤더명
객체 포인터
객체의 주소 값을 가지는 변수
포인터로 멤버에 접근할 때, p->멤버 형식으로 접근함
사용 방법
- 포인터 변수 선언
- 클래스명 *변수
- 포인터 변수에 주소 표기 하기
- &객체 이름
- 객체 포인터로 멤버 접근
- ->
예시 코드
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
class CirclePointer {
int radius;
public:
CirclePointer() { radius = 1; }
CirclePointer(int r) { radius = r; }
double getArea();
};
double CirclePointer::getArea() {
return 3.14 * radius * radius;
}
int main(){
//객체 포인터
CirclePointer donut;
CirclePointer pizza(30);
//객체 이름으로 멤버 접근
cout << donut.getArea() << endl;
//객체 포인터로 멤버 접근
CirclePointer *p;
p = &donut;
cout << p->getArea() << endl; //donut의 getArea 호출
cout << (*p).getArea() << endl; //donut의 getArea 호출
p = &pizza;
cout << p->getArea() << endl; // pizza의 getArea 호출
cout << (*p).getArea() << endl; // pizza의 getArea 호출
}
결과
1
2
3
4
5
3.14
3.14
3.14
2826
2826
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.