I'm FanJae.

[C++] Inheritance(상속) 본문

C++/Basic

[C++] Inheritance(상속)

FanJae 2024. 8. 20. 22:03

※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.

 

1. Inhertance

#include <string>
class Student
{
    std::string name;
    int age;
    int id;
};
class Professor
{
    std::string name;
    int age;
    int major;
};
int main()
{
    Student s;
    Professor p;
}

- 학사 관리 프로그램을 만들고 있는 상태에서, Student, Professor 등 필요한 클래스를 설계중이다.

- 여기서 Student, Professor 등이 가지는 공통된 속성(name,age)이 있다.

- 이를 매번 적어주기 보단 공통된 것으로 묶어지면 훨씬 더 관리가 용이하다.

 

class Person
{
      std::string name;
      int age;
};
class Student : public Person
{
    std::string name;
    int age;
    int id;
};
class Professor : public Person
{
    std::string name;
    int age;
    int major;
};
int main()
{
    Student s;
    Professor p;
}

기반 클래스인 Person으로 부터 상속받은 멤버가 있다.

- 이와 같이 기반 클래스인 Person으로 부터, name과 id를 물려 받는 것을 확인이 가능하다.

- 이와 같이 타입을 확장해서 새로운 타입을 설계하는 문법이다.

 

1-1. 장점

- 코드의 중복을 줄일 수 있다.

- upcasting, 가상함수, 다형성, 인터페이스 등 다양한 개념을 활용해서 객체지향 설계 기술을 사용할 수 있다.

 

※ 상속은 대부분의 객체지향 언어가 지원한다.

C++ class Student : public Person
C# class Student : Person
Java class Student extends Person
Python class Student (Person)

 

1-2. Base Class & Derived Class

- 상속을 표현하는 그림에 대해서 이해하는 것이 매우 중요하다.

- 이때, Person과 같은 Class를 특정 Class에게 상속의 대상으로 사용되는 Base Class(기반 클래스)라고 한다.

- 그리고, 그 아래에 Student 같이 상속을 받아오는 Class를 Derived Class(파생 클래스)라고 한다.

 

1-3. C++ 언어가 지원하는 3개의 접근 지원자

private 자신의 멤버 함수와 friend 함수에서 접근 가능
파생 클래스 멤버 함수 에서는 접근 안됨
protected 자신의 멤버 함수와 friend 함수
파생클래스 멤버 함수와 friend 함수에서 접근 가능
멤버가 아닌 함수에서는 접근 안됨.
public 모든 함수에서 접근 가능
class Base
{
private: int a;
protected: int b;
public:  int c;
};
class Derived : public Base
{
public:
    void df()
    {
         a = 10; // error
         b = 10; // ok
         c = 20; // ok
    }
};
int main()
{
    Derived de;
    de.a = 10; // error
    de.b = 10; // error
    de.c = 10; // ok
}

- Protected인 경우, public 처럼 바로 접근을 하는 것은 불가능하다 멤버 함수를 이용해서 접근을 하는것은 가능하다.


2. Constructor in Inhertance

#include <iostream>
using namespace std;
class Base
{
    int data;
public:
    Base()       { cout << "Base()"    << endl; }
    Base(int a)  { cout << "Base(int)" << endl; }
    ~Base()      { cout << "~Base()"   << endl; }
};

class Derived : public Base
{
public:
    Derived()       { cout << "Derived()"    << endl; }
    Derived(int a) : Base(a) { cout << "Derived(int)" << endl; }
    ~Derived()      { cout << "~Derived()"   << endl; }
};

int main()
{
    Derived d1();
    Derived d2(5);    
}

- 위 예제는 상속에서의 생성자 호출의 원리이다. 상당히 중요하므로, 잘 알아놔야될 것 같다.

- 위와 같은 코드가 있다고 하면, Derived 타입의 객체 d1을 생성하면, Base의 생성자도 호출된다.

- 호출이 될때의 순서는 기반 클래스인 Base가 먼저 생성되고, 그 뒤에 파생 클래스인 Derived가 생성되는 순서이다.

- Derived d2(5)와 같이 인자를 넣어 부를 경우에도 Base 생성자는 항상 인자가 없는 디폴트 생성자가 생성된다.

- Derived() 생성자를 호출하면, 이들이 우선 기반 클래스에 생성자를 부르도록 처리해준다.

- Derived()의 소멸자를 호출할 때도, 소멸자 마지막 부분에 기반 클래스의 소멸자를 호출하는 코드를 생성해 정리해준다.

- 이와 같이, 생성자를 부를때는 먼저 기반 클래스의 생성자 호출이 일어난 이후, 파생 클래스를 생성자를 호출한다.

- 반면, 소멸자는 파생 클래스에서 여러 작업이 진행된 이후, 기반 클래스의 소멸자가 마지막에 호출한다.

 

※ 기본적으로 컴파일러가 생성해주는 코드는 항상 기반 클래스의 디폴트 생성자를 호출한다.

※ 다른 버전의 생성자를 호출하려면 기반 클래스 다른 버전의 생성자를 호출하는 코드를 직접 작성해야 한다.

 

2-1. 기반 클래스(Base)에 디폴트 생성자가 없는 경우

- 파생 클래스의 생성자에서 기반 클래스(Base) 생성자를 호출하는 코드를 반드시 작성해야한다.

#include <iostream>
using namespace std;

class Base
{
    int data;
public:
    //  Base()      : data(0) { } 기본 생성자 없음
    Base(int a) : data(a) { }
    ~Base() { }
};

class Derived : public Base
{
    int data2;
public:
    Derived() : Base(0), data2(0) { } 
    Derived(int a) : Base(a), data2(a) { }
    ~Derived() { }
};

int main()
{
    //    Derived d;
    Derived d(5);

}

- 위처럼 기반 클래스의 기본 생성자가 없으면, 직접 만들어서 추가해야한다.

Dervied() : data2(0), Base(0) {}

- 기반 클래스 생성자 호출을 멤버 초기화 리스트 가장 앞쪽에 놓는것이 관례이다.

- 뒤에 놓아도 오류가 발생하지 않지만, Base(0)이 먼저 실행되므로, 가독성을 위해 기반 클래스 생성자를 앞에 두자.

 

2-2. 기본 생성자가 없는 경우도 많다.

#include <string>

class Person
{
    std::string name;
    int age;
public:
    Person(const std::string& n, int a) : name(n), age(a) 
    {
    }
};

class Student : public Person
{
    int id;
public:
    Student(const std::string& n, int a, int id) : Person(n, a), id(id) {}
};

int main()
{
    Student s1;
    Student s2("kim", 20, 100);
}

- Default 생성자가 없는 상황일때 더 코드가 안전한 경우도 존재한다.

- 이럴 경우, 파생 클래스의 생성자에서 기반 클래스 생성자로 인자를 보내줄 수 있도록 처리해준다.

Student(const std::string& n, int a, int id) : Person(n, a), id(id) {}

- 이와 같이 보내주는 방법을 상속을 할 때 많이 사용한다.

 

 

'C++ > Basic' 카테고리의 다른 글

[C++] Abstract class, Interface  (0) 2024.08.21
[C++] Upcasting, Virtual Function  (0) 2024.08.21
[C++] Copy Constructor  (0) 2024.08.19
[C++] this, Reference return  (0) 2024.08.18
[c++] const member function, mutable  (0) 2024.08.17
Comments