220916 C++ #7

김혜진·2022년 9월 16일
0

C++

목록 보기
7/12

C++ #7

상속

상속의 장점

계층의 명확성

  • 각 클래스 간의 역할 관계를 명확하게 정의
    회사 조직도의 상하 관계를 명확하게 구분하는 것처럼 클래스 간의 상속 관계 또한 계층의 명확성을 보여준다.

코드의 재사용성

  • 자식 클래스는 부모 클래스로부터 상속을 받으면 반복적인 중복 코드를 피할 수 있다.
    자식 클래스인 Regular와 Temporary는 Employee 클래스를 재사용 했다고 할 수 있다.

확장성

  • 상속을 통해 확장이 용이하다.
    기존의 기능을 변경하는 경우는 재정의하여 새로운 클래스를 정의한다.

UML 다이어그램 - 클래스 다이어그램


상속되지 않는 멤버

생성자와 소멸자

  • 생성자와 소멸자는 자식 클래스로 상속되지 않는다.

  • 부모 클래스는 어떠한 자식 클래스에 상속을 하여도 부모 클래스 입장에서는 알 수 없다. 즉, 초기화 루틴 공유가 불가능하다.
    상속한 멤버는 부모 입장에서 자식이 죽을 쑤든 밥을 먹든 상관할 수 없다. 유산을 물려주었다는 선에서 땡이다.

  • friend 멤버
    부모 클래스의 friend 멤버는 자식 클래스로 상속되지 않는다.
    부모 클래스의 friend 멤버가 상속 된다면 자식 클래스 입장에서 원하지 않은 멤버들을 상속받게 된다.
    부모님의 친구가 내 친구가 될 수는 없다.

상속 관계의 특성

자식 클래스의 객체 생성 및 소멸

  • A객체를 생성하는 경우

    클래스의 상속 관계는 A가 최상위 클래스이고, B, C 순서이다.

  • B 객체를 생성하는 경우

    B 객체를 생성하기 전에 상위 클래스가 있는지 확인한다.
    상위 클래스로 A 클래스가 있으므로 A 객체를 먼저 생성한 후 B 객체를 생성

  • C 객체를 생성하는 경우

    상위 클래스로 A, B 클래스가 있으므로 객체 순서는 A, B, C

  • 객체 소멸 순서

    소멸 시에는 생성 시와 반대로 하위 클래스가 먼저 소멸되고, 이후 상위 클래스가 소멸된다.

부모 클래스의 멤버 접근

  • 클래스 멤버 변수로 사용 시
    protected : 데이터 외부에서는 접근할 수 없고, 상속 받은 자식 클래스에서는 접근이 가능.
    protected는 외부에서 바라보았을 때, private와 같은 속성이지만, 상속 받은 자식 클래스 입장에서는 public과 같은 속성을 갖고 있다.


멤버 함수의 오버라이딩(Overriding)

  • 오버라이딩의 의미
    오버라이딩이란 사전적 의미로 '~위에 덮어쓰다.' 또는 '~에 우선한다'는 의미를 가지고 있다.
    부모 클래스에서 정의한 멤버함수가 있다면 이를 자식 클래스에서 그대로 상속받되, 내용을 변경하여 새로운 기능을 만드는 것.

부모가 추상클래스이거나 인터페이스인 경우 오버라이딩을 해야 함.

  • 멤버함수 오버라이딩의 조건
    ① 이름이 같아야 한다.
    ② 매개변수의 타입 및 개수가 같아야 한다.
    ③ 반환 타입이 같아야 한다.

오버라이딩을 하는 함수와 부모 함수는 겉은 완전 똑같아야하고, 내용만 달라야 한다.


부모 클래스와 자식 클래스 사이의 변환

  • 부모 클래스의 자식 클래스 객체 포인터 접근
    부모 클래스 객체 포인터는 자식 클래스의 객체 접근이 가능
    부모 클래스 객체 포인터를 통해 자식 클래스 객체 포인터를 제어

자식 객체가 부모 객체에 주소값을 넘겨준다.

  • 부모 클래스로 형변환


다형성

가상함수(Virtual Function)

가상함수란

  • 가상함수란 자식 클래스에서 오버라이딩 될 것으로 예상되는 멤버함수를 의미한다.
  • 상속 관계에서 부모 클래스와 자식 클래스 모두에게 같은 이름의 멤버 함수가 존재하되, 자식 클래스의 멤버함수를 재정의 할 수 있었다.
  • 상속성의 문제점은 부모 클래스의 객체를 통해 자식 클래스에서 오버라이딩 된 함수를 호출할 수 없다.
  • 가상 함수는 이러한 문제점을 해결한다.

즉 부모 클래스의 객체를 통해서 자식 클래스에서 오버라이딩 한 함수를 호출할 수 있다는 말이다.

class Employee
{
public:
	Employee();
	Employee(const char* pName, const char* pAddr);
	~Employee();
	void DisplayEmployee();
	virtual double PayCheck() const // 가상함수
	{
		return 0.0;
	}
protected: // private(보안) - protected(보호) - public(개방)
		   // 내부에서만 공유하는 protected , 부모만 protected
	const char* strName;
	const char* strAddr;
};


class Department // 객체관리
{
private:
	int count;
	Employee* emp[10]; // 클래스의 주소값을 받아서 저장할 것

public:
	Department()
	{
		count = 0;
	}
	void AddEmployee(Employee& obj)
	{
		emp[count] = &obj; //emp[0], emp[1], emp[2]
		count++;
	}
	void Display() const
	{
		for (int i = 0; i < count; i++)
		{
			cout << "급여 : " << emp[i]->PayCheck() << endl;
		}
	}
};


...
...


void main()
{
	//Employee emp("kim", "nyom");
	//emp.DisplayEmployee();

	Regular rgl("kim", "seoul", 300);
	//cout << "급여 : " << rgl.PayCheck() << endl;

	SalesMan slm("park", "kasan", 300, 50);
	//cout << "급여 : " << slm.PayCheck() << endl;

	Temporary tmp("lee", "incheon", 20, 30);
	//cout << "급여 : " << tmp.PayCheck() << endl;


/*
	Employee* emp = (Employee*)&tmp; // Regular rgl을 강제형변환으로 emp에 넣음
	cout  << "급여 : " << emp->PayCheck() << endl; // Regular의 PayCheck를 원했지만 Employee의 PayCheck 출력
	// 이 문제를 해결하려면 가상함수를 사용하면 된다.

	// 왜 이렇게 할까?
	// 코드는 그대로 있고 어떤 객체를 넣어주냐에 따라서 결과가 다르게 나오기 때문이다. => 다형성
*/

	Department dept;
	dept.AddEmployee(rgl);
	dept.AddEmployee(tmp);
	dept.AddEmployee(slm);
	dept.Display();

}
profile
알고 쓰자!

0개의 댓글