생성자란 



객체가 생성될 때마다 객체 내부와 외부에 초기화해야 할 속성들이 있습니다.
하지만 프로그램에는 많은 객체가 있기때문에, 개발자가 놓칠 수 있는데
이럴때 사용하는 것이 생성자 입니다.

생성자란 객체가 생성된 직후에 자동으로 호출되는 함수입니다.



상속 클래스의 생성자 호출순서 



객체가 생성될 때 부모생성자가 먼저 호출이되고 
자식의 생성자가 호출이 된다.

하지만 사라질때는 자식의 생성자가 먼저 삭제가 되고
부모의 생성자가 삭제가 된다.

생성자가 소멸할때는 마치 C언어의 이중포인터 같다.
간단하게 포인터를 A->B->C를 가르킨다라고 해볼 때

여기에서 B가 먼저 사라진다면 더이상A의 입장에서 C로 가는 길은 
사라졌기 때문에 C는 메모리안 어딘가에 남아있게 되어, 
메모리 누수가 생기게 될 것이다.
메모리 누수란 ? 컴퓨터 프로그램을 수행할 때 동적으로 할당된 메모리를 적절하게 회수하지 못하여, 사용할 수 있는 메모리의 크기가 줄어드는 현상이다.



또, 생성자는 클래스의 이름과 같이 생성하여야합니다.
생성자를 생성하는 패턴은 다음과 같습니다 !

 

기본생성자

#include <iostream>
using namespace std;

class Person {
public:
    string name;
    int age;

    // 기본 생성자 ==> 지금 보시면 생성자와 클래스의 이름은 같습니다.
    Person() {
        name = "Unknown";
        age = 0;
    }

    void display() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};

int main() {
    Person p; // 기본 생성자 호출
    p.display();
    return 0;
}

 

다음은 매개변수가 있는 생성자입니다.

 

 Person(string n, int a) {
        name = n;
        age = a;
    } // 매개변수가 있는 생성자

 

다음은 기본매개변수가 있는 생성자입니다.

Person(string n = "DefaultName", int a = 18) {
        name = n;
        age = a;
    } // 기본매개변수가 있는 생성자

 

 

클래스가 생성이 될 때 생성자는 바로 생깁니다. 다음의 예시를 보면 알 수 있습니다.

#include <iostream>
using namespace std;

class Person {
public:
    string name;
    int age;

    // 기본 생성자
    Person() {
        name = "Unknown";
        age = 0;
        cout << "생성자 !!" << endl;
    }

   
};

int main() {
    Person p; // 기본 생성자 호출
   
    return 0; 
}

위의 코드를 실행한 결과는 

실행결과

 

다음과 같은데, 단순히 메인함수에서 person p만 선언했을 뿐인데, 

생성자가 생기면서 출력이 되었음을 볼 수 있습니다.

이는 정적할당이 원인이며 자세한 내용은 추후에 공부할 예정입니다.

 

#include <iostream>
using namespace std;

class character {
public : 
    character() {
        cout << "character 클래스 생성자" << endl;
    }

};

class skill : public character{
public : 
    skill() {
        cout << "skill 클래스 생성자" << endl;
        skill(10, 10); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    }
    skill(int x, int y) : location{x,y} {
        cout << "skill 클래스 생성자 매개변수" << endl;
    
    }
    void show_location() {
        cout << "위치 : x , y = " << location[0] << location[1] << endl;
    }

private: 
    int location[2];
};





int main() {
    skill s;
    s.show_location();
   
    return 0; 
}

 

해당 코드에서 skill() 생성자 내의 skill (10,10) 을 보면 원래의 의도는 나는 초기값을 10,10으로 설정하겠어!

였지만 실행결과는 달랐습니다.

 

실행결과

이점을 보면서 의아한 점이 2개가 있었습니다. 왜 생성자가 2번 생겼는지? 그리고 위치값이 왜 제대로 들어가지 않는지?

그 이유는 다음과 같았습니다.

 

가장먼저 skill s를 선언하는 순간 클래스가 부모생성자 ->자식생성자로 생기게 됩니다.

그 후에 생성자 내부에서 skill(10,10)을 실행하는데 이 때 객체를 지역변수에 저장하지 않았기 때문에 

skill 매개변수 생성자에서 생성되면서 값을 전달하지 못하는 상황이 벌어집니다.

 

따라서 위치를 제대로 받을 수가 없는데 이를 해결하기 위해 다음과 같은 초기화 방법을 사용했습니다.

 

 

 

 

class skill : public character{
public : 
    skill() : skill(10,10) {
        cout << "skill 클래스 생성자" << endl;
      
    }
    skill(int x, int y) : location{x,y} {
        cout << "skill 클래스 생성자 매개변수" << endl;
    
    }
    void show_location() {
        cout << "위치 : x , y = " << location[0] << "," << location[1] << endl;
    }

private: 
    int location[2];
};

 

skill생성자 옆에  : 이라는 접근지정자를 설정해서 skill매개변수생성자에 접근할 수 있게 하여 skill을 원하는 값으로 초기화 해줄수 있었습니다.

실행 결과

 

마지막으로

class character {
public : 
    character() : a(1), b(2) {
        cout << "character 클래스 생성자" << endl;
      
    }
    void showcharacter() {
        cout << a << "," << b << endl;
    }
  
private : 
    int a;
    int b;

};


character() 생성자 내에서 해당하는 a,b의 값을 코드처럼 수정할 수 있다. 

 

 

다음 공부 할것 : 
 가상함수, 가상함수가 필요한 이유, 정적할당,동적할당 에 대해 공부할 예정입니다.

그 다음의 목표 : 

힙메모리와 스택메모리에 대해 제대로 알고 넘어가기 , 포인터와 레퍼런스의 차이 

+ Recent posts