" /> C++ 4주차 생성자와 소멸자 | BlackWerf's Blog
포스트

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인 원 소멸


예시 코드에서의 실행 순서

  1. 프로그램 로딩 - globalDonut, globalPizza 객체 생성
  2. main 함수 실행 - mainCircle1, mainCircle2 객체 생성
  3. func 함수 실행 - fDonut, fPizza 객체 생성
  4. func 함수 종료 - fDonut, fPizza 객체 소멸
  5. main 함수 종료 - mainCircle1, mainCircle2 객체 소멸
  6. 프로그램 종료 - 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 라이센스를 따릅니다.