본문 바로가기
c++

[C++]상속(Inheritance)의 이해

by goblin- 2023. 5. 14.

상속을 하게 되면, 상속의 대상이 되는 클래스의 멤버까지도 객체 내에 포함이 된다.

 

#include <iostream>
#include <cstring>
using namespace std;

class Person{
private:
    int age;
    char name[50];
public:
    Person(int myage, char *myname) : age(myage){
        strcpy(name, myname);
    }
    void WhatYourName() const{
        cout<<"My name is "<<name<<endl;
    }
    void HowOldAreYou() const{
        cout<<"I'm"<<age<<" years old"<<endl;
    }
};

class UnivStudent : public Person{
private:
    char major[50];
public:
    UnivStudent(char *myname, int myage, char * mymajor) : Person(myage, myname){
        strcpy(major, mymajor);
    }
    void WhoAreYou() const{
        WhatYourName();
        HowOldAreYou();
        cout<<"My major is "<<major<<endl<<endl;
    }
};

int main(void){
    UnivStudent ustd1("Lee",22, "Computer eng.");
    ustd1.WhoAreYou();

    UnivStudent ustd2("Yoon", 21, "Electronic eng.");
    ustd2.WhoAreYou();
    return 0;
}

결과

My name is Lee
I'm22 years old
My major is Computer eng.

My name is Yoon
I'm21 years old
My major is Electronic eng.

 

위의 예제에서

    UnivStudent(char *myname, int myage, char * mymajor) : Person(myage, myname){
        strcpy(major, mymajor);
    }

UnivStudent 생성자에서 Person 생성자를 초기화하였다 그 이유는 UniveStudent 클래스의 생성자는 자신이 상속한 Person 클래스의 멤버를 초기화할 의무를 지닌다. 그래서 UnivStudent의 생성자는 Person의 생성자를 호출하는 형태로 Person 클래스의 멤버를 초기화하는 것이 좋기 때문에 초기화시켰다.

 

용어정리

Person                    <->      UnivStudent

상위클래스               <->      하위클래스

기초(base) 클래스   <->     유도(derived) 클래스

슈퍼(super) 클래스   <->     서브(sub) 클래스

부모 클래스               <->     자식 클래스

 

 

유도 클래스의 객체 생성과정

#include <iostream>
using namespace std;

class SoBase{
private:
    int baseNum;
public:
    SoBase() : baseNum(20){
        cout<<"SoBase()"<<endl;
    }
    SoBase(int n) : baseNum(n){
        cout<<"SoBase(int n)"<<endl;
    }
    void ShowBaseDate(){
        cout<<baseNum<<endl;
    }
};

class SoDerived : public SoBase{
private:
    int derivNum;
public:
    SoDerived() : derivNum(30){
        cout<<"SoDerived()"<<endl;
    }
    SoDerived(int n) : derivNum(n){
        cout<<"SoDerived(int n)"<<endl;
    }
    SoDerived(int n1, int n2) : SoBase(n1), derivNum(n2){
        cout<<"SoDerived(int n1, int n2)"<<endl;
    }
    void ShowDerivData(){
        ShowBaseDate();
        cout<<derivNum<<endl;
    }
};

int main(void){
    cout<<"case1.... "<<endl;
    SoDerived dr1;
    dr1.ShowDerivData();
    cout<<"------------------"<<endl;
    cout<<"case2....." <<endl;
    SoDerived dr2(12);
    dr2.ShowDerivData();
    cout<<"------------------"<<endl;
    cout<<"case3...... "<<endl;
    SoDerived dr3(23, 24);
    dr3.ShowDerivData();

    return 0;
}

결과

case1.... 
SoBase()
SoDerived()
20
30
------------------
case2.....
SoBase()
SoDerived(int n)
20
12
------------------
case3...... 
SoBase(int n)
SoDerived(int n1, int n2)
23
24

위의 코드를 살펴보면 case1에서 SoDerived 객체만 생성하였지만 결과를 보면 SoBase의 값이 20이 들어가 있는 것을 볼 수 있다. 따라서 유도 클래스의 객체생성 과정에서 기초 클래스의 생성자가 호출되었다는 것을 볼 수 있다. 유도클래스의 생성자에서 기초 클래스의 생성자를 호출을 명시하지 않으면, 기초 클래스의 void 생성자가 호출된다는 사실 또한 알 수 있다.

 

 

protected 선언과 세 가지 형태의 상속

protected로 선언된 멤버변수는 이를 상속하는 유도 클래스에서 접근이 가능하다.

 

상속에는 public 상속, protected 상속, private 상속 이 있지만 public상속만 있다고 해도 될 정도로 public 외의 나머지 상속은 거의 쓰이지 않는다.