[Rookiss C++] 생성자와 소멸자

황교선·2023년 4월 2일
0

cpp

목록 보기
17/19

생성자

객체를 생성할 때 기본 자료형처럼 초기값을 주게하는 멤버함수

class 클래스이름
{
public:
    클래스이름(); // 매개변수 없는 생성자
    클래스이름(자료형 매개변수이름); // 매개변수 있는 생성자
}

특징

  • 생성자는 특별한 멤버함수임
  • 생성자명은 클래스명과 동일함
  • 생성자는 자료형을 지정하지 않음
  • 생성자의 호출은 명시적이지 않음
  • 생성자는 객체를 선언할 때 컴파일러에 의해 자동으로 호출됨
  • 객체의 초기화란 멤버변수의 초기화를 의미

기본 생성자

생성자를 명시적으로 정의하지 않으면 컴파일러가 만드는 매개변수 없는 생성자

  • 아무 일도 하지 않기 때문에, 멤버변수에 쓰레기 값이 저장됨
  • 생성자를 하나라도 만들면 기본 생성자는 만들어지지 않음
    • 매개변수 없는 생성자, 매개변수 있는 생성자 상관 없음
class Specialty
{
    // 생성자가 어떤 것도 없으면 기본 생성자가 자동 생성됨
}

매개변수 없는 생성자

class Specialty
{
public:
    Specialty() // Initialize 함수의 이름만 바꾸고 반환형을 지움
    {
        cout << "매개변수 없는 생성자 호출" << endl;
        m_posX = 0;
        m_posY = 0;
        spawnCount++;
    }
protected:
    int m_posX;
    int m_posY;
    static int spawnCount;
}

int Specialty::spawnCount = 0;
int main()
{
    Specialty a;
}
// 출력 결과
// 매개변수 없는 생성자 호출

매개변수 있는 생성자

  • 매개변수를 1개만을 받는 생성자를 타입 변환 생성자라고 부르기도 함
    • 이는 객체를 매개변수의 자료형으로의 암시적 형변환에 사용되기에 주의해야함
    • explicit 키워드를 통해 암시적 형변환을 막을 수 있음
class Specialty
{
public:
    Specialty()
    {
        m_posX = 0;
        m_posY = 0;
        spawnCount++;
    }
    Specialty(int value) // 정수 매개변수 하나를 받는 생성자
    {
        m_posX = value;
        m_posY = value;
        spawnCount++;
    }
    Specialty(int x, int y) // 정수 매개변수 두 개를 받는 생성자
    {
        m_posX = x;
        m_posY = y;
        spawnCount++;
    }
protected:
    int m_posX;
    int m_posY;
    static int spawnCount;
}

int Specialty::spawnCount = 0;
int main()
{
    Specialty b(1);
    Specialty c(1, 2);
}
// 출력 결과
// 매개변수 1개 생성자 호출
// 매개변수 2개 생성자 호출

생성자 오버로딩

생성자도 함수의 일종이므로 매개변수의 개수나 자료형을 달리해서 여러 번 정의할 수 있는 것

  • 위의 매개변수 있는 생성자를 통해서 생성자 오버로딩한 것임
  • 만약 매개변수 없는 생성자가 없고, 매개변수 있는 생성자가 있을 때, 객체를 인자 없이 호출하면 컴파일 에러가 남

생성자에 기본 매개변수 값 지정하기

class 클래스이름
{
public:
    클래스이름(int 매개변수이름 = 0); // 객체를 생성할 때 인자를 적지 않으면 이 생성자가 불리며 0이라는 값을 인자로 넣어준 것처럼 됨
}

생성자의 콜론 초기화

  • 초기화 리스트라고도 함
  • 생성자 파라미터 이후 삽입됨
  • 콜론으로 시작하고, 초기화할 멤버 변수를 쉼표로 구분하여 나열
  • 세미콜론으로 끝나지 않음
  • const의 초기화도 가능함
  • 초기화 리스트에 나열된 순서와 상관없이 멤버가 선언된 순서에 따라 초기화됨
class 클래스이름
{
public:
    클래스이름(); // 매개변수 없는 생성자
    클래스이름(자료형 매개변수이름); // 매개변수 있는 생성자
}

클래스이름::클래스이름(자료형 매개변수, 자료형 매개변수2) : 멤버변수(매개변수), 멤버변수2(매개변수2)
{

}

복사 생성자

이전 글에서 얕은 복사와 깊은 복사에 대해서 설명했었다. 복사 생성자가 깊은 복사를 하기 위함이고 이전 글에서 복사 대입 연산자와 같이 포인터 변수에 들어있는 값 자체 또한 복사하기 위해서 사용된다.

사용 시점

  • 객체가 함수에 인자로 전달될 때
  • 함수가 객체를 반환값으로 반환할 때
  • 새로운 객체를 같은 클래스 타입의 기존 객체와 똑같이 초기화할 때
클래스이름(const 클래스이름& 매개변수이름); // 참조형이기에 복사하는 것의 값을 변경하지 않기 위해 const 키워드 삽입
class Specialty
{
public:
    Specialty(const Specialty& original)
    {
        cout << "복사 생성자 호출" << endl;
        m_posX = original.m_posX;
        m_posY = original.m_posY;
        spawnCount++;
    }
// 멤버변수 생략
}

객체를 인자로 받는 함수

// 함수를 정의하고 선언할 때 매개변수로 객체가 들어가는 상황
반환형 함수이름(클래스 객체이름); // 매개변수로 복사 생성자 호출됨

함수에 넣은 인자도 매개변수에 복사될 때 복사 생성자가 호출된다. 그래서 만약 객체의 복사 비용이 크거나, 새로운 지역 객체로 만들어야할 필요가 없다면 참조 객체로 선언하여 사용하는 것이 좋다. 객체를 반환할 때도 동일하다.

void Test(Specialty b)
{

}

int main()
{
    Specialty a;
    cout << "직전 Test" << endl;
    Test(a);
    cout << "직후 Test" << endl;
}
// 출력 결과
// 매개변수 없는 생성자 호출 // a 변수의 생성자
// 직전 Test
// 복사 생성자 호출 // 매개변수 b 변수의 생성자, 복사 생성자가 호출됨
// 소멸자 호출 // 매개변수 b 변수의 소멸자
// 직후 Test
// 소멸자 호출 // a 변수의 소멸자

Test 함수를 호출할 때 매개변수 b에 복사 생성자를 호출하여 a의 값이 복사되는 것을 볼 수 있다.

소멸자

객체가 소멸할 때 실행되는 멤버함수

class 클래스이름
{
public:
    ~클래스이름(); // 소멸자
}

특징

  • 소멸자는 멤버함수임
  • 소멸자도 생성자처럼 클래스명을 사용
  • 소멸자와 생성자를 구분하기 위해 이름 앞에 ~ 기호를 붙임
  • 소멸자는 자료형을 지정하지 않음
  • 소멸자의 호출은 명시적이지 않음
  • 소멸자는 객체 소멸 시 자동으로 호출됨
  • 소멸자는 매개변수를 지정할 수 없음
  • 소멸자는 매개변수를 지정할 수 없기에 오버로딩할 수 없음
class Specialty
{
public:
    // 생성자 생략
    ~Specialty()
    {
        cout << "소멸자 호출" << endl;
        spawnCount--;
    }
// 멤버변수 생략
}
int main()
{
    Specialty a;
    Specialty b(1);
    Specialty c(1, 2);
    Specialty d(a);
    Specialty e = a;
}
// 출력 결과
// 매개변수 없는 생성자 호출
// 매개변수 1개 생성자 호출
// 매개변수 2개 생성자 호출
// 복사 생성자 호출
// 복사 생성자 호출
// 소멸자 호출
// 소멸자 호출
// 소멸자 호출
// 소멸자 호출
// 소멸자 호출

main 함수의 끝에 도달할 때 5개의 객체 또한 지역변수이므로 같이 소멸되어 소멸자 내의 출력문이 호출되는 것을 볼 수 있다. main 함수가 아니더라도 새로 정의한 함수 내에서 지역변수로 객체를 사용한 후 그 함수가 종료될 때 그 객체의 소멸자가 호출된다.

profile
성장과 성공, 그 사이 어딘가

0개의 댓글