My Profile Photo

DongChanS's blog


수학과 학생의 개발일지


파이썬 유저를 위한 C++ (8) - 클래스 (2) - 생성자, 소멸자

11) 클래스(2)

11-1. 생성자

파이썬의 __init__() 함수는 인스턴스가 생성된 이후에 멤버변수들의 초기화를 위해서 단 한번만 호출되는 메서드입니다.

소위 생성자라고 불리는데, C++에서도 이러한 개념이 있습니다.

자바와 비슷하게 C++에서는,

  • 생성자의 이름은 클래스 이름과 같습니다. (ex, Book클래스의 생성자는 Book())
  • 반환값이 없음에도 void타입을 명시하지 않습니다.
  • 반드시 public 영역에서 선언되어야 합니다.

11-2. 생성자의 선언, 호출

생성자의 원형과, 선언 방식은 일반적인 멤버함수와 비슷합니다.

class Book {
private:
    int id_; // 이런식으로 _를 붙여서 명명하는것을 권장하는듯합니다.
    int price_;
public:
    Book(int, int); // 원형
};

Book::Book(int id, int price){
    id_ = id;
    price_ = price;
} // 선언

하지만, 생성자의 호출은 다양한 방법이 있습니다.

int main(){
    Book my_book(1234, 10000);
    // Book my_book = Book(1234, 10000);
    // Book my_book = {1234, 10000};
}

주석을 친 두 가지 방법 모두 가능한 방법인데,

마지막 방법은 매우 신기합니다. 배열 표기법을 객체에 대입한다는게 사실 잘 와닿지는 않지만 아무튼 된다고 합니다.

11-3. 디폴트 생성자

저번 포스트에서는 생성자에 대한 언급도 안하고 객체를 생성할 수 있었습니다.

왜냐하면 디폴트 생성자가 멤버변수를 초기화해주기 때문입니다.


Default constructor

  • 매개변수를 가지지 않음.

  • 그렇지만 멤버변수들을 기본값(0, NULL, 빈 문자열, …)등으로 초기화시켜줌.

  • 생성자를 단 하나도 정의하지 않을 때에만 존재함.

    (컴파일러가 자동으로 만들어줍니다.)

class Book {
private:
    int id_, price_;
public:
    void print();
};

void Book::print(){
    std::cout << id_ << " " << price_; 
}

int main(){
    Book my_book; 
    // Book my_book() 은 에러를 발생시킵니다.
    my_book.print();
}
// 출력값, 전부 0으로 초기화된 모습입니다.
0 0

하지만, 우리가 생성자를 정의함으로 인해 디폴트 생성자가 없어진다고 해서 크게 걱정하실 필요는 없습니다.

왜냐하면 생성자 오버로딩을 통해서 비슷한 기능을 구현하게 만들 수 있기 때문입니다.

11-4. 복사 생성자

파이썬에는 copy 라이브러리의 deepcopy 함수를 통해서 객체의 깊은 복사를 할 수 있습니다.

이와 비슷하게, C++에서는 복사 생성자를 통해서 다른 객체와 동일한 값들을 가지지만, 주소는 다른 객체를 생성할 수 있습니다.

class Book {
private:
    int id_, price_;
public:
    void print();
    Book(Book &Book);
	Book(int, int);
};

void Book::print(){
    std::cout << "id : " << id_ << " price : " << price_ << std::endl;
    std::cout << "객체의 주소 :" << this<< std::endl;
}

Book::Book(Book &Book){
    id_ = Book.id_;
    price_ = Book.price_; 
    // 신기하게도 private인데 불구하고 접근이 가능함! 
} // 복사 생성자

Book::Book(int id, int price){
	id_ = id;
	price_ = price;
} // 원래 생성자

int main(){
    Book my_book(1234, 10000); 
    my_book.print();
    Book your_book(my_book);
    your_book.print();
}
// 출력값
id : 1234 price : 10000
객체의 주소 :0x7ffe36aa3948
id : 1234 price : 10000
객체의 주소 :0x7ffe36aa3940

11-5. 부록) Copy constructor에서 private 변수에 접근가능한 이유

참고링크 : https://stackoverflow.com/questions/4117002/why-can-i-access-private-variables-in-the-copy-constructor

Book::Book(Book &Book){
    id_ = Book.id_;
    price_ = Book.price_; 
    // 신기하게도 private인데 불구하고 접근이 가능함! 
} 

왜냐하면 access modifier는 object level이 아니라 class level에서 작동하기 때문입니다.

그래서 같은 클래스에 있는 두 object는 서로의 데이터에 접근할 수 있습니다.

  • 효율성 때문에 이런 개념이 생겨났습니다.

    만약 객체단위로 access modifier가 적용되어있다면, this == other 를 비교하기 위해서 엄청나게 많은 연산을 해야하기 때문입니다.

11-5. 소멸자

파이썬에서는 __del__이라는 매직메서드가 있듯이, C++에도 소멸자라는 비슷한 개념이 있습니다.

소멸자는 객체가 메모리상에서 사라질 때에 발생하는 함수인데요,

  1. 객체가 메모리상에서 사라지는 경우들
  • 정적 변수(startic, extern) : 프로세스의 data 영역에 저장되며, 프로그램이 종료될 때 사라짐.
    • 이 때는, 컴파일러가 소멸자를 호출합니다.
  • 자동 변수(지역 변수) : 프로세스의 stack 영역에 저장되며, 해당 블록 호출이 끝난 후 사라짐.
  • 동적할당된 포인터 : new 연산자를 통해서 프로세스의 heap 영역에 저장되며, delete 연산자를 사용한 뒤에 제거됨.
  1. 소멸자의 특징
  • 인수를 가지지 않음.
  • 반환값이 없으나, void 형으로 선언하지 않음.
  1. 문법 : ~을 붙여서 사용
~Book();
comments powered by Disqus