언어/C++

[C++] 1. 멤버이니셜라이저(feat. const 변수), 2. 생성자와 소멸자를 이용한 동적할당, 3. this 포인터

study_memo 2023. 9. 25. 01:30

1. 멤버이니셜라이저란?

멤버이니셜라이저 (변수초기화방식) : 선언과 동시에 초기화한다.

 

함수 : 초기화 할 변수(초기화 될 값)

형식으로 선언해준다. 

 

예시로 const 변수와 함께 멤버이니셜라이저를 살펴보자. 

//const 변수는 반드시 선언 시 초기화를 해야 한다. 즉, 초기화하지 않으면
//컴파일 에러가 발생한다. 따라서 class나 struct의 멤버변수를 const로 선언 시에는
//반드시 초기화 히스트(initialize list)를 사용해야 한다. 


//정상적인 코드
class ConstExample{
	const int num;
	ConstExample(void) : num(3); //이것이 멤버이니셜라이저이다.
};

//컴파일 에러가 나는 코드
class ConstExample{
	const int num;
	ConstExample(void){
    	num = 3; //컴파일 에러 발생
    }
};

2. 생성자와 소멸자를 이용한 동적할당 -> 생성자와 멤버이니셜라이저 동시 사용!

아래 코드 주석을 보면 생성자를 이용하여 어떻게 동적할당을 하고, 

소멸자를 이용하여 메모리 반환을 하는지 잘 알 수 있다. 

#include <iostream>
using namespace std;

class nameCard {
    //변수는 private으로 지정
    string *person_name, *company_name, *phone_number; 
    //성명, 회사 이름, 전화번호 //동적할당은 포인터 선언을 해줘야 함.
public: //생성자와 소멸자는 public으로 지정
    void ShowNameCardInfo(); 
    //함수는 메인함수에서 인자를 받아야하므로 private으로 선언하면 오류남. 
    nameCard(string person_name, string company_name, string phone_number); 
    //생성자도 하나의 함수이므로 매개변수 써줘야 함.
    ~nameCard(); //소멸자
};

nameCard::nameCard(string person_name, string company_name, string phone_number)
:person_name(new string(person_name)), company_name(new string(company_name)), 
phone_number(new string(phone_number)) 
//멤버이니셜라이저 사용
{ //동적할당하는 생성자
    /*string* person_name = new string;  
    string* company_name = new string;
    string* phone_number = new string;*/
   // -> 이렇게 하면 안 됨.  NameCard에 이미 선언된 거를 또 선언해주는 꼴..
 //멤버이니셜라이저 사용하면 this 사용 안해도 됨, 멤버이니셜라이저는 함수 내에서 선언x 함수 밖에서
}

nameCard::~nameCard() { //동적할당을 해제하는 소멸자
    delete person_name;
    delete company_name;
    delete phone_number;
}

void nameCard::ShowNameCardInfo(){
    cout << "이름 : "<<*(this->person_name) <<'\n';
    //person_name이 포인터 변수이므로 this ->임. 그냥 변수일 때는 마침표쓰면 됨. 
    cout << "회사 : " << *company_name << '\n'; 
    //애스터리스크 안 쓰면 company_name의 주소값이 나옴
    cout << "전화번호 : " << *phone_number << '\n';
}

int main(void) {
    nameCard manClerk("Lee", "ABCEng", "010-1111-2222");
    nameCard manAsist("Hong", "OrangeEng", "010-3333-4444");
    nameCard manSENIOR("Kim", "soGoodComp", "010-5555-6666");
    manClerk.ShowNameCardInfo();
    cout << '\n';
    manAsist.ShowNameCardInfo();
    cout << '\n';
    manSENIOR.ShowNameCardInfo();

    return 0;
}

위 코드에서 

nameCard::nameCard(string person_name, string company_name, string phone_number)
:person_name(new string(person_name)), company_name(new string(company_name)), 
phone_number(new string(phone_number)) 
//멤버이니셜라이저 사용
{ //동적할당하는 생성자
    /*string* person_name = new string;  
    string* company_name = new string;
    string* phone_number = new string;*/
   // -> 이렇게 하면 안 됨.  NameCard에 이미 선언된 거를 또 선언해주는 꼴..
 //멤버이니셜라이저 사용하면 this 사용 안해도 됨, 멤버이니셜라이저는 함수 내에서 선언x 함수 밖에서
}

이 부분을 보자.

만약 여기서 멤버이니셜라이저를 사용하지 않는다면 어떻게 될까?

아래 코드와 같이 this를 사용하면 된다.

//this 사용

nameCard::nameCard(string person_name, string company_name, string phone_number)
{ 
    this->person_name =new string(person_name);
    this->company_name =new string(company_name);
    this->phone_number =new string(phone_number);
}

3. 여기서 this가 가리키는 변수는 무슨 변수일까? ->멤버볌수를 가르킨다. 

NameCard::NameCard(const char* name, const char* company, const char* phone) 안에 있는 매개변수 가리키는 거 아님!

NameCard::NameCard(const char* name, const char* company, const char* phone) {    // 생성자
    this->name = new char[strlen(name) + 1];        // name 길이만큼 동적할당, +1은 null문자 자리// 1 추가 안해주면 메모리 오류 남
    strcpy(this->name, name);    

    this->company = new char[strlen(company) + 1];  // company 길이만큼 동적할당, +1은 null문자 자리
    strcpy(this->company, company);

    this->phone = new char[strlen(phone) + 1];      // phone 길이만큼 동적할당, +1은 null문자 자리
    strcpy(this->phone, phone);
}

참고로 

this->name = new char[strlen(name) + 1]; 은
(*this).name = new char[strlen(name) + 1]; 과 똑같다..!

아래는 전체코드이다. 

#include <iostream>
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
using namespace std;

class NameCard    // NameCard 클래스 생성
{
private:        // 멤버 변수 선언
    char* name;
    char* company;
    char* phone;
public:
    // const 안붙이면 오류 나는데 이유를 모르겠다..
    NameCard(const char* name, const char* company, const char* phone);    // 생성자
    ~NameCard();    // 소멸자
    void ShowNameCardInfo();    // 입력한 NameCard정보 출력하는 함수
};

NameCard::NameCard(const char* name, const char* company, const char* phone) {    // 생성자
    this->name = new char[strlen(name) + 1];        // name 길이만큼 동적할당, +1은 null문자 자리
                                                    // 1 추가 안해주면 메모리 오류 남
    strcpy(this->name, name);    

    this->company = new char[strlen(company) + 1];  // company 길이만큼 동적할당, +1은 null문자 자리
    strcpy(this->company, company);

    this->phone = new char[strlen(phone) + 1];      // phone 길이만큼 동적할당, +1은 null문자 자리
    strcpy(this->phone, phone);
}

NameCard::~NameCard() {        // 소멸자
    delete[]name;            // 동적할당 받은 메모리 반환
    delete[]company;
    delete[]phone;
}

void NameCard::ShowNameCardInfo() {        // 입력한 정보 출력
    cout << "이름 : " << name << endl;
    cout << "회사 : " << company << endl;
    cout << "전화번호 : " << phone << endl;
    cout << endl;
}

int main()
{
    NameCard manClerk("Lee", "ABCEng", "010-1111-2222");
    NameCard manAssist("Hong", "OrangeEng", "010-3333-4444");
    NameCard manSENIOR("KIM", "SoGoodComp", "010-5555-6666");
    manClerk.ShowNameCardInfo();
    manAssist.ShowNameCardInfo();
    manSENIOR.ShowNameCardInfo();
    return 0;
}