상속 (Inheritance)
상속은 재사용성을 높이고 다형성을 확보할 수 있는 방법입니다.
기존에 잘 디자인 된 클래스를 확장하여 새로운 목적의 클래스를 만들어 낼 수 있습니다.
어떠한 클래스가 다른 클래스를 멤버로써 포함될 때, 이를 has a 상속 이라고 합니다.
- 예 : PC는 CPU 와 RAM 을 포함한다
어떠한 클래스가 다른 클래스로 부터 파생될 때, 이를 is a 상속 이라고 합니다.
- 예 : Laptop 은 PC다
흔히 상속이라는 표현을 쓰면 is a 상속을 이야기 합니다.
"돈을 지불하다" 라는 메소드가 있습니다.
학생이 "돈을 지불하다" 라는 것과 회사원이 "돈을 지불하다"라는 것은 본질적으로 동일합니다.
전통적인 C 프로그래밍에서는 이러한 중복되는 기능은 "함수"로써 분리하기를 권장합니다.
- 코드가 여러 벌이 생기면 각각의 파트별로 유지보수가 복잡해지기 때문입니다.
C++에서도 마찬가지입니다. 그러나, C 에서는 전역에 함수를 선언하므로 어디에서나 호출할 수 있지만, C++ 에서는 "객체지향"이라는 관점에서 자료형과 관련된 메소드들은 클래스 내에 디자인하기를 권장합니다.
학생과 회사원의 공통점이면서, "돈을 지불하다"라는 메소드를 가질 수 있는 "사람"입니다.
그렇다면, Person 클래스를 부모로 Student 와 Employee 라는 파생 클래스를 디자인 할 수 있습니다.
#include <iostream>
class Person
{
private:
int money;
protected:
Person(int val)
: money(val) {}
public:
void payTo(Person& payTo,int val)
{
this->money -= val;
payTo.money += val;
}
int getMoney()
{
return money;
}
};
class Student : public Person
{
public:
Student(int val) : Person(val) {};
};
class Employee : public Person
{
public:
Employee(int val) : Person(val) {};
};
int main(int argc, char** argv)
{
Student student(100);
Employee employee(100);
std::cout << student.getMoney() << " " << employee.getMoney() << std::endl;
student.payTo(employee, 10);
std::cout << student.getMoney() << " " << employee.getMoney() << std::endl;
}
상속은 클래스를 선언할때 클래스 이름 뒤에 : 를 붙이고 상속하려는 클래스 이름을 기입합니다.
이때 private, protected, public 권한을 지정할 수 있으며, 아무것도 지정하지 않을 경우, 기본값은 private 입니다.
상속시 접근권한
- private 로 지정할 경우, 부모 클래스의 모든 멤버는 파생 클래스에서 private 로 지정됩니다.
- protected 로 지정할 경우, 부모 클래스의 public 은 protected 로 지정되며, 나머지는 부모클래스의 권한과 동일하게 지정됩니다.
- public 으로 지정할 경우, 부모 클래스의 권한지정은 파생 클래스의 멤버들에 똑같이 지정됩니다.
또한 부모 클래스의 권한은 파생 클래스안에서의 호출에도 영향을 줍니다.
-
부모 클래스에서 private 로 지정된 멤버는 파생 클래스에서도 호출할 수 없습니다.
-
protected 로 지정된 멤버는 파생 클래스 내부에서는 호출할 수 있지만,
protected 혹은 private 로 상속되기 때문에 파생 클래스 외부에서는 호출할 수 없습니다.
- public 으로 지정된 멤버는 상속시에 public 으로 상속했다면
파생 클래스 내부 혹은 외부에서 호출할 수 있으며, protected 나 private 로 상속했다면 내부에서만 호출할 수 있습니다.
만약, 위의 예제 코드에서 상속을 각각 protected 이나 private 로 지정하면, 부모 클래스에서의 지정이 public 이므로, Student 와 Employee 의 내부 메소드에서는 payTo와 getMoney 를 호출할 수 있지만, 외부에서는 호출할 수 없습니다.
권한지정 활용
Person 은 private 멤버로 int money 를, protected 멤버로 생성자를 가지고 있습니다.
생성자가 protected 이기에 외부 호출이 불가능하며, Person 은 직접 선언으로 생성할 수 없도록 제한됩니다.
- protected 는 외부에는 private, 상속 자식에게는 public 으로 지정되는 접근 제어입니다.
Student 와 Employee 는 public 으로 Person 을 상속합니다.
- private 속성이었던 money 값에 접근할 수는 없지만 protected 였던 생성자에는 접근할 수 있습니다.
- Student 와 Employee 의 생성자는 public 으로 지정되었기 때문에, Student 와 Employee 는 직접 선언이 가능해집니다.
Student(int val) : Person(val) {}; 와 같이 부모의 생성자에 매개변수를 전달했습니다.
- 부모 클래스가 기본 생성자가 없을 경우, 반드시 부모의 생성자에 매개변수를 전달해 주어야 합니다.