[C++] 08 특수 멤버 함수(Special Member Function)

김진우·2025년 5월 19일

C++

목록 보기
8/16
post-thumbnail

정의

클래스를 선언할 때 컴파일러가 자동으로 생성하는 클래스의 멤버 함수이다.
개발자가 클래스에서 따로 정의를 하지 않아도 암시적으로 선언하고 된다.

6가지의 특수 멤버 함수 종류는 다음과 같다.

  • 기본 생성자
  • 소멸자
  • 복사 생성자
  • 대입 연산자(복사 대입 연산자)
  • 이동 생성자
  • 이동 대입 연산자

생성자(Constructor)

객체가 생성될 때 자동으로 호출되는 함수이다.

생성자 특징

함수명이 구조체 혹은 클래스명과 동일해야 한다.

우리가 어떠한 변수(구조체, 클래스 포함)를 사용할 때 별다른 생성자 선언 없이 변수를 사용할 수 있다. 생성자는 따로 선언하지 않아도 기본 생성자가 선언되어 있다.

사용자가 생성자를 정의할 수도 있다. 하지만 생성자를 하나라도 만드는 순간 기본 생성자는 사라지므로 기존에 쓰던 변수가 있다면 컴파일 에러가 발생할 수 있다.

기본 생성자는 파라미터가 없는 생성자를 의미한다.

생성자 선언

class C {
	C();
    C(int a);
    C(int a, float b);
}

이렇게 생성자의 parameter에 변수 선언 시 입력받을 값을 지정할 수 있다. 앞서 함수 part에서 말한 오버로딩(Overloading)의 개념이 적용된다.

물론, 서로 다른 생성자로 처리되기 때문에 동작이 다르고 정의도 따로 해줘야 한다.

생성자는 여러 개가 선언 되었더라도 변수 선언 시 입력되는 값에 따라 하나만 실행이 된다.

생성자 정의

C::C() {
	printf("st");
}

C::C(int a) {
	printf(a);
}

C::C(int a, float b) {
	printf(a, b);
}

실제로는 출력 대신 멤버 변수를 초기화 하는 역할을 주로 한다. 생성자 3개가 다른 동작이 된다는 것을 표현하기 위해 이 예시를 작성했다.

생성자 사용

C cl1;
C cl1(5);
C cl2(1, 2);

객체 생성 시 argument로 입력하는 값에 따라 다른 생성자가 호출된다.
모든 객체는 하나의 생성자만 호출된다.


소멸자(Destructor)

객체의 수명(Life Cycle)이 끝날 때 호출되는 함수로, 메모리 정리 작업을 수행한다.

소멸자 특징

  • return이 없다.
  • Parameter를 가질 수 없다.
  • 한 클래스에 하나만 존재한다.
  • 자동 호출된다.

여러 함수의 실행이 있을 경우 메모리의 stack 구조 때문에 생성자가 호출된 반대의 순서대로 실행이 된다.

소멸자 선언

~ 키워드를 이용해 선언 가능하다.

class C {
	~C();
}

소멸자 정의

C::~C() {
	delete a;
    a = nullptr;
}

동적할당 받은 멤버 변수의 값을 반환하는 역할을 한다.

소멸자 사용

소멸자는 코드를 따로 작성하지 않아도 자동으로 실행된다.


복사 생성자

객체를 생성할 때 다른 객체의 멤버 값을 복사할 때 호출되는 생성자이다.

하나의 parameter를 갖는다. (클래스의 reference type)

복사 생성자 특징

기본적으로 얕은 복사(Shallow Copy)를 한다.

복사 생성자 선언

일반적으로 const ClassName&를 parameter로 가진 형태로 선언된다.

class C {
	C(const C& other);
}

복사 생성자 정의

깊은 복사를 위해 parameter로 받은 객체를 참조해 값을 저장한다.

C::C(const C& other) {
	this->data = new int(*other.data);
}

복사 생성자 사용

  1. 기본 선언
    아래와 같은 클래스 객체가 이미 선언되었다고 가정한다.
	C class1("new");
  1. 선언시 사용
    C class2(class1);

class1의 값을 class2에 복사한다.

  1. 초기화시 사용
	C class3 = class1;

대입처럼 보이지만 객체를 생성할 때 초기화 하는 것이므로 복사 생성자가 호출된다.

  1. 함수 인자 전달로 사용 (Call by value)
	void CopyFunction(C obj);

여기서 CopyFunction을 호출하기 위해 argument로 class가 전달될 때, 함수 매개변수를 초기화하기 위해 복사 생성자가 호출된다.

  1. 함수에서 객체 반환으로 사용
	C CopyFunction() {
    	C temp();
        return temp;
    }
    
    C class4 = CopyFunction();

함수가 객체를 값으로 반환할 경우(포인터가 아닌 경우) 복사 생성자가 호출된다.


대입 연산자 (복사 대입 연산자)

객체가 이미 생성된 이후, 다른 객체의 값을 대입할 때 호출되는 연산자 함수이다.
객체 간의 값 복사(= 대입)를 수행하며 기존 데이터를 덮어씌운다.

대입 연산자 특징

  • 함수 이름은 operator= 이다.
  • 반환형은 자기 자신 클래스의 참조형이다. (ClassName&)
  • 기본 구현은 얕은 복사(Shallow Copy)이며, 동적 할당 시에는 깊은 복사(Deep Copy)가 필요하다.

대입 연산자 선언

class C {
	C& operator=(const C& other);
};

대입 연산자 정의

C& C::operator=(const C& other) {
    if (this == &other) return *this;  // 자기 자신인지 확인

    delete data;  // 기존 리소스 해제
    data = new int(*other.data);  // 깊은 복사

    return *this;
}

대입 연산자 사용

C obj1;
C obj2;
obj2 = obj1;  // 대입 연산자 호출

이동 생성자

자원을 복사하지 않고 소유권을 이전(move)할 때 호출되는 생성자이다.
복사보다 성능이 우수하며, 특히 임시 객체를 효율적으로 처리할 수 있다.

이동 생성자 특징

  • C(C&& other) 형태로 정의된다.
  • 참조가 아닌 우측값 참조(Rvalue Reference)를 매개변수로 받는다.
  • 복사 대신 자원의 포인터가 이동하고, 원본 자원은 초기화된다.

이동 생성자 선언

class C {
	C(C&& other);
};

이동 생성자 정의

C::C(C&& other) {
    this->data = other.data;
    other.data = nullptr;  // 소유권 이전, 원본 해제
}

이동 생성자 사용

C MakeObject() {
    C temp;
    return temp;  // 이동 생성자 호출
}

C obj = MakeObject();  // 이동 생성자 or 복사 생성자 (RVO 최적화에 따라)

이동 대입 연산자

이미 존재하는 객체에 다른 객체의 자원을 이동해서 할당할 때 호출된다.
복사 대입 연산자와 유사하지만, 이동 대입은 리소스 이전을 수행한다.

이동 대입 연산자 특징

  • 함수 이름은 operator= 이다.
  • 우측값 참조 (C&&)를 인자로 받는다.
  • 기존 자원을 해제하고, 새로운 자원의 소유권을 가져온다.
  • 자기 자신 검사가 필요하다.

이동 대입 연산자 선언

class C {
	C& operator=(C&& other);
};

이동 대입 연산자 정의

C& C::operator=(C&& other) {
    if (this == &other) return *this;

    delete data;
    data = other.data;
    other.data = nullptr;

    return *this;
}

이동 대입 연산자 사용

C obj1;
obj1 = MakeObject();  // 이동 대입 연산자 호출

특수 멤버 함수 요약

이름호출 시점기본 동작주의사항
기본 생성자객체 생성 시 인자 없음기본 초기화다른 생성자 정의 시 자동 생성되지 않음
소멸자객체 소멸 시리소스 해제동적 메모리 사용 시 반드시 정의 필요
복사 생성자새 객체 ← 기존 객체로 초기화얕은 복사깊은 복사 필요 시 직접 정의
복사 대입 연산자기존 객체 ← 기존 객체얕은 복사자기 자신 검사 필수, 깊은 복사 필요 시 직접 정의
이동 생성자새 객체 ← 임시 객체 or 이동 가능한 객체포인터 이동자원 이전 후 원본 포인터를 nullptr로 설정 필요
이동 대입 연산자기존 객체 ← 임시 객체 or 이동 가능한 객체포인터 이동기존 자원 해제 + nullptr 처리 필요

0개의 댓글