지금까지는 하나의 클래스에 대해 이야기를 했습니다. 지금부터는 하나 이상의 클래스를 이야기할까 합니다. 즉, 클래스 간의 관계에 대한 이야기입니다.

 

클래스의 관계는 여러 가지가 있지만 재사용 측면에서 크게 두 가지 관계가 존재합니다.( 우리는 복잡한 것을 생각하지 않으므로 간단하게 접근합니다.)

  • 첫째, '-이다'의 관계( is_a 관계)

    • 상속(inheritance)
  • 둘째, '-가지다'의 관계( has_a 관계)

    • 포함(composition)

 

첫째, is_a 관계는 Person 클래스와 Student 클래스의 관계입니다.

  • Student(학생)은 Person(사람) 이다. 관계이기 때문에..
  • 그림으로는 아래와 같이 표현할 수 있습니다.

상속Person.png 

이때 Person 클래스를 부모(Parent) 클래스라 하고 Student, Professor 클래스를 자식(child) 클래스라 합니다.

 

 

둘째, has_a 관계는 Car 클래스와 Radio 클래스의 관계입니다.(이것은 다음에 진행합니다. --;)

  • Car(자동차)는 Radio(라디오)를 가진다. 관계이기 때문에..
  • 그림으로는 아래와 같이 표현할 수 있습니다.

포함car.png 

 

 1, 상속

상속은 부모 클래스의 모든 내용(속성과 행동)을 자식 클래스가 물려 받는 것입니다.

위 그림에서 Person의 속성(멤버 변수)와 행동(멤버 함수)을 Student가 물려 받습니다. 그리고 자신만의 상태와 행동을 추가하여 내용을 확장합니다.

그래서 상속을 이용하면 코드를 재상용하여 효율적으로 클래스를 생성할 수 있습니다.

 

Student 클래스를 만들기 위한 간단한 예제코드를 볼까요?

첫째, 상속을 사용하지 않는 Student 클래스 정의

class Student
{
    char name[20];
    int age;
    int grade;
public:
    void Eat( ) {   }
    void Study( ) { }
};

void main( )
{
    Student std1;
}

 학생은 사람이므로 사람으로서 필요한 모든 내용(속성과 행동)을 Student 클래스가 정의하고 있습니다. 이렇게 되면 Professor 클래스를 정의할 때도 사람에 필요한 모든 내용을 정의해야 합니다. 그러면 코드 중복이 발생하여 여러 가지 불이익을 받게 됩니다.

 

Student 객체의 그림입니다.

상속없는_student_객체.png 

 

 

둘째, 상속을 사용한 Student 클래스 정의

class Person
{
    char name[20];
    int age;
public:
    void Eat( ) {   }
};
class Student : public Person
{
    int grade;
public:
    void Study( ) { }
};

void main( )
{

    Person person1;

 

    Student student1;

}

여기서 Person 클래스가 이미 존재한다고 가정한다면 Student 클래스를 정의하는 것은 위쪽 예제보다 훨씬 간단합니다. 속성 grade와 행동 Sudent()만 정의할 뿐이니까요. 그리고 부가적으로 따라오는 이득도 만만치 않습니다. 문법적으로 상속은 " : public Person"와 같이 합니다.(빨간색 부분)

 

Person 객체와 Student 객체의 그림입니다.

당연한 이야기지만 Student 객체는 위쪽 상속을 사용하지 않는 객체의 속성, 행동과 같은 객체가 만들어 집니다. 상속을 사용해서 Student 클래스를 정의한 것뿐이니까요.

상속없는_student_객체(2).png 

 

 

2, 함수 재정의(function overriding)

 함수 재정의란 부모 클래스에 정의된 멤버 함수를 자식 클래스에서 다시 정의하는 것을 말합니다.

 

예로 아래와 같은 Person 클래스가 있다고 가정합니다.

#include <iostream>
using namespace std;

class Person
{
    char name[20];
    int age;
public:
    Person(const char* n, int a)
    {
        strcpy(name, n);
        age = a;
    }
    void Eat( ) {   }
    void Print( )
    {
        cout << "name : " << name <<", " <<"age : " << age << endl;
    }
};
void main( )
{
    Person person1("김영수", 20);

    person1.Print( );
}
  1. name : 김영수, age : 20

 person1의 Print() 멤버 함수는 이름과 나이를 출력합니다.

 

이때 학생을 정의하기 위한 Student 클래스가 필요합니다.

이미 Person 클래스가 존재하므로 Student 클래스는 Person을 상속받아 만들기로 결정합니다.

아래와 같이..

#include <iostream>
using namespace std;

class Person
{
    char name[20];
    int age;
public:
    Person(const char* n, int a)
    {
        strcpy(name, n);
        age = a;
    }
    void Eat( ) {   }
    void Print( )
    {
        cout << "name : " << name <<", " <<"age : " << age << endl;
    }
};
class Student : public Person
{
    int grade;
public:
    Student(const char* n, int a, int g):Person(n,a), grade(g)     {
    }
    void Study( ) { }
};
void main( )
{
    Student student1("김학생", 20, 1);

    student1.Print( );
}
  1. name : 김학생, age : 20

 그리고 학생 객체 student1을 만들어 학생의 정보를 출력(Print() 호출)하지만 Print() 함수는 grade의 정보를 출력하지 못합니다.

Print()함수는 Person의 메소드로 grade의 어떠한 내용도 알지 못하기 때문입니다.

한마디로 Person 클래스보다 Student 클래스가 더 구체화된 클래스이므로 Print() 함수의 기능도 Student에 맞게 더 구체화 시켜야 합니다.

그래서 부모 클래스(Person)의 함수(Print())를 자식 클래스(Student)에서 재정의하는 것입니다.

아래 예제와 같이...

#include <iostream>
using namespace std;

class Person
{
    char name[20];
    int age;
public:
    Person(const char* n, int a)
    {
        strcpy(name, n);
        age = a;
    }
    void Eat( ) {   }
    void Print( )
    {
        cout << "name : " << name <<", " <<"age : " << age << endl;
    }
};
class Student : public Person
{
    int grade;
public:
    Student(const char* n, int a, int g):Person(n,a), grade(g)     {
    }
    void Study( ) { }
    void Print( ) // 함수 재정의
    {
        Person::Print(); // 이름과 나이를 출력하고
        cout << "grade : " << grade << endl; // 학년도 출력합니다.
    }
};
void main( )
{
    Student student1("김학생", 20, 1);

    student1.Print( );
}
  1. name : 김학생, age : 20
    grade : 1

 Student 클래스에서 Print()함수를 재정의하여 이름과 나이도 출력하고(Person::Print()) 학년도 출력합니다. 재정의 함수에서 부모의 함수를 호출하려면 접근 연산자(::)를 사용해야 합니다. ( Person::Print() <=  이렇게... )

아니면 재귀함수 호출이 되겠죠?

 
출처 : http://coolprogramming.springnote.com/pages/3422007

+ Recent posts