[C++] 생성자(constructor)
[객체 생성방법]
1. 일반적인 객체 선언 방식( STACK -> 메모리관리 X )
// 1. 일반적인 변수 선언 방식(STACK)
SimpleClass sc;
이 방식으로 하면 객체는 stack 에 올라가고
해당 중괄호를 벗어나면 객체는 알아서 소멸됨.
2. 동적할당(HEAP -> new/delete)
// 2. 동적할당(HEAP)
SimpleClass* ptr = new SimpleClass();
이 방식으로 하면 객체는 heap 에 올라가고
이때는 사용자가 delete를 해주지 않는 이상 소멸되지 않음
즉, 직접 메모리 관리를 해줘야함
[객체 생성 과정]
이는 생성자가 호출되었을때 실행되는 과정들임
1. 메모리 공간의 할당
2. Member Initializer를 이용한 멤버변수 초기화
3. 생성자의 몸체부분 실행
[생성자 constructor]
0) 리턴타입이 없다
1) 클래스 이름과 동일한게 생성자다
2) 객체 생성 시 딱 한번 호출된다
3) 생성자도 함수이므로 오버로딩이 가능
서로 다른 생성자란 판단은 매개변수의 개수와 타입으로 판단되어진다
(모두 이름은 클래스이름으로 똑같기 때문에 구별할 방법이 매개변수 개수 밖에 없다)
4) return type이 다른건 생성자 오버로딩의 조건이 되지 않는다
class SimpleClass {
private :
int num;
public :
SimpleClass() {
num = 0;
}
SimpleClass(int n) : num(n) {
// empty
}
void setter(int n) {
num = n;
}
int getter() {
return num;
}
};
[1. default constructor]
SimpleClass() {
//empty
}
객체가 생성되기 위해서는 반드시 하나의 생성자가 호출되어야한다
따라서 생성자를 하나도 정의해놓지 않았으면 디폴트 생성자(public) 가 자동으로 삽입된다
디폴트 생성자는 인자를 받지 않으며 내부적으로 아무런 일도 하지 않는다.
(즉, 코드가 하나도 없다. body is empty)
디폴트 생성자는 생성자가 하나도 정의되어있지 않을때에만 자동으로 추가된다
생성자가 한 개라도 명시되어있으면 자동추가 안됨
기본생성자는 정의된 생성자가 한 개도 없을때 컴파일러가 알아서 넣어주는, 자동으로 배정되는 생성자임
매개변수도 없고 몸체도 비어있는 진짜 그냥 객체만 1개 생성하고 끝나는 생성자이다
그럼 얘는 언제 호출될까?
SimpleClass sc; ---> SimpleClass sc();
// or
SimpleClass sc = new SimpleClass();
이렇게 매개변수를 하나도 안주면 기본생성자가 호출된다.
2. Member Initializer
아래 Point 클래스와 Rectangle 클래스가 있다.
class Point {
private:
int x, y;
public:
Point(int x, int y) {
this->x = x;
this->y = y;
}
};
class Rectangle {
private:
Point upLeft;
Point upRight;
public:
Rectangle(const int& x1, const int& y1, const int& x2, const int& y2) : upLeft(x1,y1), upRight(x2,y2)
{
//empty
}
여기서 Rectangle 생성자의 " : upLeft(x1,y1), upRight(x2,y2) " 이 부분이 멤버 이니셜라이저임
이 코드가 Point(int x,int y) 생성자를 호출하고 이로써 Rectangle의 멤버로 있는 upLeft와 upRight 객체가 초기화됨
[Member Initializer 특징]
멤버변수로 선언된 객체의 생성자 호출에 사용된다!
멤버변수로 선언된 객체나 객체가 아닌 기본자료형 모두 이 방법으로 초기화할 수 있다!
말그래도 생성자를 통해 멤버를 초기화할때 쓰는 방법
그냥 body에서 직접 초기화해도 되지만 이 방법으로 하는게 좋다
1) 성능에 약간 이점이 있다
굉장히 미세한 차이지만 member initializer를 사용하면
int num = n;
이렇게 선언과 동시에 초기화되는데
member initializer를 사용하지 않으면
int num;
num=n;
이렇게 2번에 작업이 들어가야하기 때문에 더 느리다.
2) 초기화 대상을 명확히 인식할 수 있다
[생성자의 Default 매개변수]
생성자 호출 시 인자를 넣지 않으면, "미리 정해준 인자값"이 대신 들어가게끔 만드는 것
class MyClass {
private:
int x; int y;
public:
MyClass(int a = 0, int b = 0, int c = 0) {
x = a;
y = b;
}
};
유용한 예시다
MyString(const char* in = nullptr){
// code
if(in==nullptr) return;
// code
}