4. 생성자 (Constructor)
1) 생성자의 개념
- 생성자(Constructor)는 객체가 생성될 때 자동으로 호출되는 특수한 멤버 함수이다.
- 객체는 반드시 하나의 생성자를 거쳐야 “생성된 객체”로 간주한다.
- 생성자의 이름은 클래스명과 동일하게 선언한다.
- 반환형이 없고 값을 반환하지 않으며, 기본적으로 public 접근 제어를 갖는다.
- 생성자는 객체 생성 시 단 한 번만 호출된다.
- 오버로딩이 가능하며, 매개변수에 기본값 설정도 할 수 있다.
- 생성자를 정의하지 않을 경우, 컴파일러가 기본 생성자(Default Constructor)를 자동 삽입한다.
⛏️ 생성자와 Init 함수의 차이
· Init()은 명시적으로 호출해야 하는 일반 함수이다.
· 반면 생성자는 객체 생성과 동시에 자동 호출된다.
✅ 예시
class Ex {
public:
int a, b;
// 생성자 정의
Ex() {
a = 0;
b = 0;
}
Ex(int x, int y) {
a = x;
b = y;
}
};
int main() {
Ex e1; // 기본 생성자 호출
Ex e2(10, 20); // 오버로딩된 생성자 호출
}
⚠️ 함수 원형 선언과 생성자 호출의 혼동
Ex ex(); // ❗이것은 객체 생성이 아닌 함수 원형 선언이다.
· 위와 같은 문법은 C++에서 인자를 받지 않는 함수의 원형으로 인식된다.
· 따라서 객체 생성을 위해서는 반드시 괄호 없이 Ex ex; 형태로 작성해야 한다.
2) 멤버 이니셜라이저(Member Initializer)
- 생성자에서 멤버 변수 또는 멤버 객체의 초기화를 위해 사용하는 구문이다.
- : 뒤에 나오는 구문을 통해 초기화를 수행한다.
- ⛏️ 성능적으로도 이점이 있으며, 특히 const 변수나 참조자는 반드시 이 방식으로 초기화해야 한다.
✅ 예시
class Ex {
const int id;
int& ref;
public:
Ex(int x, int& r) : id(x), ref(r) {} // 멤버 이니셜라이저 사용
};
✅ 비교
// 멤버 이니셜라이저 방식
Ex(int n) : a(n) {}
// 생성자 본문에서 초기화
Ex(int n) {
a = n;
}
· 두 방식은 동작상 유사하나, 멤버 이니셜라이저는 컴파일 단계에서 바이너리 코드 최적화가 가능하다.
3) 기본 생성자(Default Constructor)
- 매개변수가 없는 생성자를 의미한다.
- 사용자가 생성자를 하나도 정의하지 않으면, 컴파일러가 자동으로 삽입한다.
- 생성자가 하나라도 정의되어 있으면, 기본 생성자가 필요할 경우 직접 명시해야 한다.
✅ 주의
· malloc()을 이용해 객체를 생성하면 생성자가 호출되지 않는다.
· new 연산자를 사용해야 생성자가 자동으로 호출된다.
4) private 생성자
- 클래스 내부 또는 특정 함수에서만 호출 가능한 생성자이다.
- 객체의 생성을 제한하거나, 싱글톤 패턴 등을 구현할 때 유용하다.
✅ 예시
class OnlyFactory {
private:
OnlyFactory() {} // 외부에서는 생성 불가
public:
static OnlyFactory create() {
return OnlyFactory(); // 내부에서만 생성 가능
}
};
5. 소멸자(Destructor)
- 객체가 소멸될 때 자동으로 호출되는 함수이다.
- 클래스명 앞에 ~ 기호를 붙여서 선언한다.
- 반환형과 매개변수가 없으며, 오버로딩이 불가능하다.
- 객체가 소멸될 때 리소스 해제 등의 정리 작업에 사용된다.
✅ 예시
class Ex {
public:
~Ex() {
std::cout << "객체가 소멸되었습니다." << std::endl;
}
};
6. 객체 배열
1) 일반 배열
- 클래스 객체를 배열 형태로 선언할 수 있다.
- Ex ex[10]; 형태로 선언하면, 내부적으로 기본 생성자가 10번 호출된다.
- 생성자에 인자를 넘기려면 포인터 배열을 사용해야 한다.
✅ 주의
· 생성자에 매개변수가 있는 경우, 해당 생성자를 사용할 수 없기 때문에 기본 생성자가 반드시 필요하다.
2) 포인터 배열
- 객체를 포인터로 관리할 경우, 배열 요소마다 서로 다른 생성자를 호출할 수 있다.
✅ 예시
Ex* ex[3];
ex[0] = new Ex(1, 2);
ex[1] = new Ex(3, 4);
ex[2] = new Ex(5, 6);
7. this 포인터
- this는 자기 자신 객체의 주소를 담고 있는 포인터이다.
- 주로 매개변수명과 멤버변수가 겹칠 때 사용한다.
- 멤버 이니셜라이저에서는 사용할 수 없다.
✅ 예시
class Ex {
int x;
public:
Ex(int x) {
this->x = x; // 매개변수와 멤버변수 구분
}
Ex* getThis() {
return this;
}
};
1) 참조 반환(Self-Reference)
- 자기 자신 객체를 참조자로 반환하고자 할 때 사용한다.
✅ 예시
class Ex {
public:
Ex& getSelf() {
return *this; // 자기 참조 반환
}
};
✅ 마무리 정리
1️⃣ 생성자는 클래스명과 동일하며 반환형이 없다.
2️⃣ 생성자 오버로딩과 기본값 설정이 가능하다.
3️⃣ 멤버 이니셜라이저는 const 및 참조자 초기화에 필수이다.
4️⃣ 소멸자는 ~기호를 사용하며, 반환형·매개변수 없이 정의한다.
5️⃣ 객체 배열은 기본 생성자를 필요로 하며, 포인터 배열로 유연하게 관리할 수 있다.
6️⃣ this 포인터는 멤버 함수 내에서 자기 자신 객체의 주소를 의미한다.
💻 전체 예제 코드: 생성자, 소멸자, this 포인터 통합 예제
#include <iostream>
#include <string>
using namespace std;
// 📌 클래스 정의
class Ex {
private:
const int id; // const 멤버 변수 (멤버 이니셜라이저로만 초기화 가능)
int x, y; // 일반 멤버 변수
string name; // 문자열 멤버 변수
public:
// ✅ 1. 기본 생성자
Ex() : id(0), x(0), y(0), name("default") {
cout << "[기본 생성자] 객체 생성됨: id=" << id << ", name=" << name << endl;
}
// ✅ 2. 오버로딩된 생성자 (멤버 이니셜라이저 사용)
Ex(int _id, int _x, int _y, string _name)
: id(_id), x(_x), y(_y), name(_name) {
cout << "[오버로딩 생성자] 객체 생성됨: id=" << id << ", name=" << name << endl;
}
// ✅ 3. this 포인터 사용 - 멤버 변수 설정
void setValues(int x, int y) {
this->x = x; // 매개변수 x와 멤버변수 x 구분
this->y = y;
}
// ✅ 4. this 포인터를 통해 자기 자신 반환 (Self-reference)
Ex& getSelf() {
return *this;
}
// ✅ 5. 정보 출력 함수
void printInfo() const {
cout << "객체 정보: id=" << id << ", name=" << name
<< ", x=" << x << ", y=" << y << endl;
}
// ✅ 6. 소멸자
~Ex() {
cout << "[소멸자] 객체 소멸됨: id=" << id << ", name=" << name << endl;
}
};
int main() {
// ✅ 1. 기본 생성자 호출
Ex obj1;
// ✅ 2. 오버로딩 생성자 호출
Ex obj2(1, 10, 20, "hello");
// ✅ 3. this 포인터로 멤버값 설정
obj1.setValues(100, 200);
obj1.printInfo();
// ✅ 4. Self-reference 활용
Ex& ref = obj2.getSelf();
ref.printInfo();
// ✅ 5. 객체 배열 생성 (기본 생성자 필요)
Ex arr[2]; // 기본 생성자 2번 호출됨
// ✅ 6. 포인터 배열을 통한 객체 생성
Ex* pArr[2];
pArr[0] = new Ex(2, 11, 22, "A");
pArr[1] = new Ex(3, 33, 44, "B");
// ✅ 7. 동적으로 생성된 객체 정보 출력
pArr[0]->printInfo();
pArr[1]->printInfo();
// ✅ 8. 메모리 해제
delete pArr[0];
delete pArr[1];
return 0;
}
📦 예상 출력 결과
[기본 생성자] 객체 생성됨: id=0, name=default
[오버로딩 생성자] 객체 생성됨: id=1, name=hello
객체 정보: id=0, name=default, x=100, y=200
객체 정보: id=1, name=hello, x=10, y=20
[기본 생성자] 객체 생성됨: id=0, name=default
[기본 생성자] 객체 생성됨: id=0, name=default
[오버로딩 생성자] 객체 생성됨: id=2, name=A
[오버로딩 생성자] 객체 생성됨: id=3, name=B
객체 정보: id=2, name=A, x=11, y=22
객체 정보: id=3, name=B, x=33, y=44
[소멸자] 객체 소멸됨: id=2, name=A
[소멸자] 객체 소멸됨: id=3, name=B
[소멸자] 객체 소멸됨: id=0, name=default
[소멸자] 객체 소멸됨: id=0, name=default
[소멸자] 객체 소멸됨: id=1, name=hello
[소멸자] 객체 소멸됨: id=0, name=default
'Language > C++' 카테고리의 다른 글
| 📌 Chapter 06 - 특수 멤버와 한정자(Special Member & Specifier) (1) | 2025.08.25 |
|---|---|
| 📌 Chapter 05 - 복사 생성자(Copy Constructor) (2) | 2025.08.11 |
| 📌 Chapter 04 - 클래스 고급 개념 - 01 (1) | 2025.08.09 |
| 📌 Chapter 03 – 클래스 기초 (2) | 2025.08.06 |
| 📌 Chapter 02 - C와 비교하는 C++ 2 (0) | 2025.07.15 |