• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

[9:00 부근] Mother class 멤버 변수를 Child class의 initializer list 에서 초기화하는 부분

20.12.31 16:33 작성 조회수 222

0

안녕하세요, 아래의 코드에서 error 가 발생하는 부분에 대해서 문의드려요. 
강의에서 교수님께서 debugger로 찍어주셨듯이 호출되는 순서는 아래와 같은데요.

Mother class의 initializer list ->Mother class의 constructor -> Child class의 initializer list->Child class의 constructor.

error가 나는 부분에서는 mother class의 멤버 변수가 이미 초기화되어 메모리를 차지하고 있는데 child class에서 초기화할 수 없는게 이해가 되지 않습니다.

강의에서 교수님께서 계속 반복적으로 말씀해주시는데 제가 뭔가 놓친게 있는걸까요? 호출 순서랑 아래의 에러 발생하는 이유가 매칭이 되지 않네요. 

항상 답변주셔서 감사합니다.

#include <iostream>
using namespace std;

class Mother
{
public:
	int m_i;
public:
	Mother()
		:m_i(0)
	{
		cout << "Mother constructor" << endl;
	}
};

class Child :public Mother
{

public:
	double m_d;
public:
	Child()
		:m_d(2.0),m_i(1) //error 발생
	{
		cout << "Child constructor" << endl;
	}
};

int main()
{
	Child c1;
	return 0;
}

답변 3

·

답변을 작성해보세요.

6

안소님의 프로필

안소

2021.01.02

질문자님께서 생각하신게 맞습니다.

Child 의 초기화 리스트에서 초기화는 아직 안하고 메모리만 잡아둔 후에! 부모생성자로 올라가서 부모로부터 물려받는 m_i 같은 멤버를 메모리 할당받고 초기화하게 됩니다. 이 부모생성자 작업이 모두 끝난 후에야 다시 돌아와서 이전에 할당받아놓은 m_d 메모리에 2.0 값을 넣어주는 초기화를 하게 됩니다.

부모 생성자로 올라가기 전에 초기화 리스트에 있는 m_d와 m_i 의 메모리를 할당 받으려하는데 아직 부모 생성자를 호출한게 아니라서 Child 입장에서 m_i 이 뭔지 모르기 때문입니다.(즉, 아직 상속 처리가 되기 전입니다.) m_d는 Child의 ㅇ멤버라는 것을 알고 있어서 문제 없습니다.

따라서 멤버의 초기화는 본인만의 클래스 안에서만 해주는게 좋을 것 같습니다! 

(덧붙여서 제가 위에 쓴 답변 맨 위의 "error가 나는 부분에서는 mother class의 멤버 변수가 이미 초기화되어 메모리를 차지하고 있는데 child class에서 초기화할 수 없는게 이해가 되지 않습니다." 부분은 질문자님의 글을 위에 복사해두고 보면서 답변을 쓴건데 제가 실수로 안지운 것입니다.. 이제야 발견했네요 ㅎㅎ..)

감사합니다. 질문자님도 새해 복 많이 받으세요🥰

6

안소님의 프로필

안소

2020.12.31

error가 나는 부분에서는 mother class의 멤버 변수가 이미 초기화되어 메모리를 차지하고 있는데 child class에서 초기화할 수 없는게 이해가 되지 않습니다.

안녕하세요.

Child 의 초기화리스트에서 m_i(1) 을 마주하게 되는 그 시점에선 Child는 m_i 를 모릅니다. m_i는 메모리를 차지하고 있는 상태가 아닙니다. 그래서 에러가 발생한 것입니다. 순서에 대해서 차근 차근 말씀 드릴게요!

main 함수에서 Child c1; 를 통해 Child 클래스로부터 객체 c1 가 메모리에 실존하게끔 생성하는 과정을 시작합니다. 우선 문제가되는 m_i(1)은 없다고 가정하고 시작해보겠습니다.

1. 먼저 Child의 초기화 리스트부터 확인합니다. m_d(2.0)를 확인하고 Child 멤버 m_d 의 메모리만 잡아 놓습니다. 초기화는 하지 않고 단순히 메모리만 할당 받아 놓는 것입니다. (이 메모리에 2.0 이라는 값을 넣어주는 초기화는 부모생성자 호출이 모두 끝난 후에 이루어집니다.)  👉 강의 5:50 참고해보시면 m_d 메모리가 생기긴 했는데 아직 초기화가 이루어지지 않아 쓰레기값이 들어있는것을 확인할 수 있습니다.

2. 그리고 부모 생성자를 호출합니다. Mother() 가 실행이 되는데 Mother 의 초기화 리스트를 확인합니다. m_i 멤버를 확인하고 m_i 의 메모리를 잡아놓습니다. 👉 강의 6:52 m_i 의 메모리가 생겼고 아직 초기화가 이루어지지 않아 쓰레기값이 들어있는것을 확인할 수 있습니다.

3. Mother의 부모는 없으므로 더 호출해야 할 부모 생성자는 없습니다. 따라서 초기화 과정을 시작합니다. 잡아놓은 m_i 에 m_i(0) 0을 집어넣어 초기화시켜주고 Mother 생성자의 중괄호 부분(Mother Constructor 출력 부분) 까지 실행을 마치고 Mother 생성자 실행을 종료합니다. 이렇게 c1 객체의 부모로부터 상속받은 부분의 메모리 할당과 초기화를 마쳤습니다.  👉 강의 6:57 중괄호에 들어오게 되면서 m_i의 초기화가 이루어졌습니다.

4. 다시 Child 생성자로 돌아와 그제서야 m_d 메모리에 2.0 이라는 값이 초기화가 됩니다. 👉 강의 7:25 참고해보시면 Mother() 끝나고 돌아온 직후에 m_d는 초기화가 이루어지지않아 여전히 쓰레기값이 들어있는 것을 확인할 수 있습니다. 그리고 마찬가지로 Child() 생성자의 중괄호에 들어가게 되면서 초기화가 이루어지게 됩니다. 

정리하자면

A(조상)-B(부모)-C(자식) 이런 가계도가 있고 C 타입의 객체를 생성한다고 가정해보면

C->B->A 순으로 멤버들의 메모리가 차례대로 잡힙니다.(초기화는 안되고 메모리 할당만 받아 놔서 쓰레기값 들어있는 상태) C인 나만의 멤버, B 부모님으로부터 상속 받은 멤버, A 조부모님으로부터 상속 받은 멤버 이 순서로 메모리만 잡아둔다고 생각하시면 됩니다. 

그리고 나서야! 생성자를 통해 메모리에 유효한 값을 넣어주는 '초기화'과정과 생성자의 중괄호 부분이 실행되는 순서는 A->B->C 순으로 조상부터 차례차례 이루어집니다. 

설명이 길었는데 결론적으로 그 부분에 에러가 발생한 이유는, 일단 Mother() 부모생성자 호출 전에 Child 의 멤버들의 메모리를 잡아놓는 과정부터 먼저 거치게 되는데 m_i 는 메모리가 아직 잡히지 않은 상태이므로 Child 타입인 c1 객체에서 아직 이 m_i 메모리는 존재하지 않는 상태이기 때문입니다. 위 과정의 순서에서 보시면 1번부터 문제가 생기게 된거에요!

초기화는 이루어지지 않은, 쓰레기 값이 들어있는 메모리 자체만 먼저 잡아 두고 부모생성자 호출이 다 끝난 다음에야 초기화가 이루어진다고 생각하시면 됩니다. '메모리만 먼저 잡아 두고' 👉 이 과정에서 m_i 얘는 누구지? 하게 되서 에러가 발생하신거에요!

1

choiiohc1님의 프로필

choiiohc1

질문자

2021.01.02

정말 상세한 답변 감사합니다!

public:
    double m_d;
Child()
		:m_d(2.0), m_i(0)
	{
		cout << "Child constructor" << endl;
	}

그럼 위 코드의 child 클래스의 초기화 리스트에서, 해당 변수들에 대한 메모리를 미리 할당해 놓는데(초기화X), m_d는 double형으로 알려져있지만, m_i는 아직 어떠한 정보도 없는 상태이기 때문에 메모리를 미리 할당할 수 없어서 에러가 발생한다라고 생각하면 될까요? 

항상 답변 감사드립니다. 새해 복 많이 받으세요!