상속 (2)

Yama·2024년 1월 12일
0

어소트락 수업

목록 보기
42/55

상속의 생성자와 소멸자

	A a; 
	B b;
	C c; 
  • 기본 생성자와 기본 소멸자를 만들어서 0으로 초기화를 안해주면 쓰레기값이 들어가 있을것이다.
	A()
		: m_A(0)
	{}
	~A() {}
  • 기본생성자로 m_A를 0으로 초기화 해주었고 기본 소멸자 만들어둠.
public:
	B()
    	// 1
		: A()
		, m_B(0)
	{}
  • B클래스는 A클래스는 상속을 받았는데 B클래스를 초기화할때 부모클래스(A)까지 맴버에 다들어가서 초기화해주는것은 불편하다.
    • 상속은 그래서 받는 이유는 재활용을 하기 위해서이다.
      • 그래서 B클래스는 B클래스에서 생긴 맴버만 초기화해주면된다.
      • 상속받은 A클래스에서 A의 맴버들을 A에서 초기화해준다.
  • 상속 관계에서는 각 클래스는 본인의 맴버의 초기화만 신경 쓴다.
    • 자식 클래스가 부모 파트의 초기화를 부모 클래스의 생성자를 활용해서 한다,
  • 자식 클래스에서 부모 클래스의 생성자에 대한 명시가 따로 없다면 부모 클래스의 기본 생성자를 호출하게 된다(1번이 생략됨)

상속의 초기화.

  • 호출은 자식 클래스의 생성자부터 부모 순서로 진행하되 초기화 순서는 부모 클래스에서 자식클래스 순서로 진행됨.
    • 아키텍쳐 설계 관점에서 보면 부모의 기능을 쓰는거라 부모부터 초기화를 해줘야한다.
    • 부모의 기능을 상속을 받아서 먼저 사용할려면 초기화를 부모부터 해야한다.
  • 대기업에서 하청업체로 일을 뿌리는 느낌.
public:
	C() 
		: m_C(0)
		, B()
  • 순서를 바꿔도 부모의 초기화부터 한다.
    • 우선순위가 초기화우선.

상속의 소멸

  • 소멸할때는 자식 클래스 부터 소멸이 된다.
    • 부모가 먼저 지워지면 자식은 부모한테 참조받을걸 모르기 떄문이다.
  • 경제가 힘들면 하청업체부터 망하는 식.

문제

class C : public B
{
public:
	C() 
		// 3
		: m_A(0) , m_B(0) , m_C(0) 
	{
    	// 1
		m_A = 0; // m_A 는 A 클래스에서 protected
        // 2
		m_B = 0; // m_B 는 B 클래스에서 private
		m_C = 0;
	}
	C()
		: m_C(0)
		, B()
	{}
	{}

};
  • 1번은 오류 없고 2번은 오류가 뜨는걸 잘케치한다. 그러나 3번은 m_A(0) , m_B(0) 오류다.
    • 초기화시에는 해당 클래스 맴버만 가능하다.

생성자 오버 로딩

  • 클래스를 만들때 처음부터 값을 넣고 싶은 경우.
    • 생성자 오버로딩한다.
public:
	// 1
	A()
		: m_A(0)
	{}
    // 2
	A(int _A)
		: m_A(_A)
	{}
	// 3
	A a1;
	// 4
	A a2();
	// 5
	A a1(10);
  • 3번은 1번의 기본 생성자를 호출한다.
  • 4번은 생성자 호출이 아니라 함수 전방 선언으로 취급한다.
  • 5번은 2번 생성자를 호출한다.
public:
	B()
		: A()
		, m_B(0)
	{}
	B(int _A, int _B)
    	// 1
		: A(_A)
		, m_B(_B)
	{}
	B b1(10, 20);
  • 1번을 명시적으로 적어야하는 이유
    • 적으면 원하는 결과가 출력됨
    • 안적으면 인자를 두개를 줘도 받은 a를 못쓴다.
	C()
		: m_C(0)
		, B()
	{}
	C(int _A, int _B, int _C)
		: B(_A, _B)
		, m_C(_C)
	{}
	C c1(10, 20, 30);
  • 마찬가지로 명시적으로 적어줘야 인자받은 만큼 _A, _B를 쓸 수 있다.

크기

  • 크기는 4,8,12다.

상속의 소멸자

// A클래스 내부
	~A()
	{
		cout << "A Class Destruction" << endl;
	}
// B클래스 내부   
    ~B()
	{
		cout << "B Class Destruction" << endl;
        // 1
		//A::~A();
	}
// C클래스 내부
    ~C()
	{
		cout << "C Class Destruction" << endl;
        // 1
		//B::~B();
	}
  • 1번은 B클래스를 상속을 받으면 기본적으로 소멸자에 생략이 되어 있다.
    • 그래서 1번을 강제적으로 호출하면 ~B소멸자를 두번호출한다.

강의 코드

#include <iostream>

using std::cout;
using std::endl;

class A
{
protected:
	int m_A;
public:
	void SetA(int _a) { m_A = _a; }
public:
	A()
		: m_A(0)
	{}

	A(int _A)
		: m_A(_A)
	{

	}

	~A()
	{
		cout << "A Class Destruction" << endl;
	}
};

class B : public A
{
private:
	int m_B;

public:
	void SetB(int _b)
	{
		m_B = _b;
	}

	int GetB()
	{
		return m_B;
	}
public:

	B()
		: m_B(0)
	{}

	B(int _A, int _B)
		: A(_A)
		, m_B(_B)
	{}

	~B()
	{
		cout << "B Class Destruction" << endl;

	}
};

class C : public B
{
private:
	int m_C;

public:
	void SetC(int _c)
	{
		m_A = _c;
		//m_B = _c;
		m_C = _c;
	}

public:
	//C() 
	//	: m_A(0), m_B(0), m_C(0) // 초기화시에는 해당 클래스 맴버만 가능
	//{
	//	m_A = 0; // m_A 는 A 클래스에서 protected
	//	m_B = 0; // m_B 는 B 클래스에서 private
	//	m_C = 0;
	//}
	C()
		: m_C(0)
	{}

	C(int _A, int _B, int _C)
		: B(_A, _B)
		, m_C(_C)
	{}

	~C()
	{
		cout << "C Class Destruction" << endl;
		B::~B();
	}
};

int main()
{
	A a; // 4  바이트
	B b; // 8  바이트
	C c; // 12 바이트

	a.SetA(10);
	b.SetA(20);
	c.SetA(30);

	b.SetB(10);
	c.SetB(10);

	c.SetC(10);

	A a1(10);
	B b1(10, 20);
	C c1(10, 20, 30);

	int size = 0;
	size = sizeof(a1);
	size = sizeof(b1);
	size = sizeof(c1);

	return 0;
}

1차 24.01.12
2차 24.01.15
3차 24.01.16
4차 24.01.17
5차 24.01.18

0개의 댓글