클래스를 선언할 때 컴파일러가 자동으로 생성하는 클래스의 멤버 함수이다.
개발자가 클래스에서 따로 정의를 하지 않아도 암시적으로 선언하고 된다.
6가지의 특수 멤버 함수 종류는 다음과 같다.
객체가 생성될 때 자동으로 호출되는 함수이다.
함수명이 구조체 혹은 클래스명과 동일해야 한다.
우리가 어떠한 변수(구조체, 클래스 포함)를 사용할 때 별다른 생성자 선언 없이 변수를 사용할 수 있다. 생성자는 따로 선언하지 않아도 기본 생성자가 선언되어 있다.
사용자가 생성자를 정의할 수도 있다. 하지만 생성자를 하나라도 만드는 순간 기본 생성자는 사라지므로 기존에 쓰던 변수가 있다면 컴파일 에러가 발생할 수 있다.
기본 생성자는 파라미터가 없는 생성자를 의미한다.
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로 입력하는 값에 따라 다른 생성자가 호출된다.
모든 객체는 하나의 생성자만 호출된다.
객체의 수명(Life Cycle)이 끝날 때 호출되는 함수로, 메모리 정리 작업을 수행한다.
여러 함수의 실행이 있을 경우 메모리의 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);
}
C class1("new");
C class2(class1);
class1의 값을 class2에 복사한다.
C class3 = class1;
대입처럼 보이지만 객체를 생성할 때 초기화 하는 것이므로 복사 생성자가 호출된다.
void CopyFunction(C obj);
여기서 CopyFunction을 호출하기 위해 argument로 class가 전달될 때, 함수 매개변수를 초기화하기 위해 복사 생성자가 호출된다.
C CopyFunction() {
C temp();
return temp;
}
C class4 = CopyFunction();
함수가 객체를 값으로 반환할 경우(포인터가 아닌 경우) 복사 생성자가 호출된다.
객체가 이미 생성된 이후, 다른 객체의 값을 대입할 때 호출되는 연산자 함수이다.
객체 간의 값 복사(= 대입)를 수행하며 기존 데이터를 덮어씌운다.
operator= 이다.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)할 때 호출되는 생성자이다.
복사보다 성능이 우수하며, 특히 임시 객체를 효율적으로 처리할 수 있다.
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 최적화에 따라)
이미 존재하는 객체에 다른 객체의 자원을 이동해서 할당할 때 호출된다.
복사 대입 연산자와 유사하지만, 이동 대입은 리소스 이전을 수행한다.
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 처리 필요 |