[11] Inheritance


Inheritance : is-a relationship
11.2継承の基礎
Studnet is a Person
Teacher is a Person
->Personが普及しているので、Personクラスを再作成します.
Child ClassにはMother Classが含まれているため、Mother Classが宣言した場合、Child Classで宣言する必要はありません.当たり前なら
クラスは、個別のヘッダファイルを作成して削除することが望ましい.
#include <bits/stdc++.h> //비추천. 편의상 작성
using namespace std; //비추천. 편의상 작성

//Person Class
class Person {
private:
    std::string m_name;
public:
    Person(const std::string& name_in = "No name") : m_name(name_in) {}

    void setName(const string& name_in) {
        //의도적인 막음. 
        m_name = name_in; //Person 에서 public 변수가 아니니까 당연함. 
    }

	// const 선언 이유. Child 클래스에서 param 으로 받아오는데 param에서 const로 불러오고 있음. 
    string getName() const {
        return m_name;
    }
};

//Student Class
class Student : public Person {
private:
    int m_intel;
public:
    // 생성자에서 initialize 할 떄 에러가 남. m_name 은 Person 의 member variable. 
    // Student에서 Person 의 constructor를 초기화하는식으로 해야함
    Student(const string& name_in = "no name", const int& intel_in = 0)
        // : m_name(name_in), m_intel(intel_in) {}
        : Person(name_in), m_intel(intel_in) {} //Studnet 생성자를 통해서  Person 생성자를 호출

    // void setName(const string& name_in) {
    //     //의도적인 막음. Person의 m_name 을 자식에서 접근하지 않도록
    //     m_name = name_in; //Person 에서 public 변수가 아니니까 당연함. 
    // }

    void setIntel(const int& intel_in) {
        m_intel = intel_in;
    }

    int getIntel() const {
        return m_intel;
    }

    friend ostream& operator << (ostream& out, const Student& student) {

        // getName이 mother. Stduent 을 const로 params로 받아오므로, getName() 뒤에 const 선언
        out << student.getName() << " " << student.getIntel();
        // out << student.m_name << " " << student.m_intel;
        return out;
    }

    void study() {
        cout << getName() << " is studying" << endl;
    }
};

//Teacher Class
class Teacher : public Person {
private:
public:
    Teacher(const string& name_in = "no name")
        : Person(name_in) {
    }

    friend ostream& operator << (ostream& out, const Teacher& teacher) {
        out << teacher.getName(); //직접 접근 불가능
        return out;
    }

    void teach() {
        cout << getName() << " is teaching" << endl;
    }
};
ChildクラスTeacherとStudioでnameを初期化する場合は、親クラスPersonクラスのジェネレータを直接呼び出して初期化できます.これについての説明は、次のChapterでさらに詳しく説明します.(ジェネレータ順序のため)
    Student(const string& name_in = "no name", const int& intel_in = 0)
        : Person(name_in), m_intel(intel_in) {}
11.3 Derived Class作成順序
作成順序
常にMatherクラスを作成した後にChildクラスを生成します.
11.2に示すように、初期化器は親クラスのメンバーを初期化することはできません.これは,Child classのイニシエータがイニシャル化されるとMotherクラスの作成者が呼び出されるためである.つまり私たちの目には.
Child() : m_d(1.0) {}
事実上.
Child() : Mother(), m_d(1.0) {}
はい.Mother classのメンバー変数はジェネレータの{}で呼び出すことができますが、initializerで呼び出すことはできません.
クラスを複数回継承する場合:
class A {
public:
    A() { cout << " A Constructor " << endl;}
};

class B : public A {
public:
    B() { cout << " B Constructor " << endl;}
};

class C : public B {
public:
    C() { cout << " C Constructor " << endl;}
};
A Constructor 
B Constructor
C Constructor
この場合、Constructorは当然Aとなり、BCの順に生成される.DestructorConstructorの逆順である.
11.4 Derived Classの作成と初期化
Child classを生成すると、Child変数+がMotherに宣言したようにメモリサイズが割り当てられます.
11.5指定者の継承とアクセス
例を挙げると、Baseクラスは以下のようになります.
class Base {
public:
    int m_public;

// protected 는 child 만 접근 가능    
protected:
    int m_protected;

private:
    int m_private;
};
class Derived : private BaseDerivedクラス内でBaseクラスのpublicおよびprivate変数にアクセスできますが、GrandChildクラス(つまりDerived Class)を継承するクラスでBaseのすべての変数にアクセスすることはできません.
class Derived : private Base {
public:
    int d_int;
    Derived() {
        m_public = 123;
        m_protected = 321;       
    }
};

class GrandChild : public Derived {
public:
    GrandChild() {
        d_int = 123;
        // Derived::m_public = 123; 불가 
        // Derived::m_protected = 123 ; 불가
    }
};
class Derived : protected Baseクラス内ではBaseクラスのpublic変数やprotected変数にもアクセスできますが、外部(main)ではアクセスできません.
11.6ブートクラスに新しい機能を追加
Skip
11.7継承関数の上書き
class Base {
private:
    int m_val;
public:
    Base(int val_) : m_val(val_) {}
    void print() {
        cout << "I'm base" << endl;
    }
    // output operator overrloading
    friend ostream& operator << (ostream& out, const Base& b) {
        cout << "this is base output" << endl;
        return out;
    }
};

class Derived : public Base {
private:
    double m_d;
public:
    Derived(int val_) : Base(val_) {}

    // override 하고 싶을 때. 
    void print() {
        cout << "I'm Derived" << endl;
    }

    // output operator overrloading
    friend ostream& operator << (ostream& out, const Derived& b) {
        //base operator 를 불러오고 싶을 때
        //이게 왜 되냐? 메모리가 사이즈가 있으면,Base + Derived니까 
        //Base에 대한 내용을 Derived가 갖고 있기 때문에 가능함! 
        cout << static_cast<Base>(b);
        cout << "this is derived output" << endl;
        return out;
    }
};

int main() {
    Base base(5);
    // base.print();
    cout << base;
    Derived derived(7);
    // derived.print();
    cout << derived;
}
11.8継承関数の非表示
継承された変数publicはクラス内で使用できます.
    // m_i 가 Derived 안에서 public이 되고, 외부에서 변경 가능함. 
    using Base::m_i;
逆に、継承された関数の使用が阻止される場合があります.
//방법 1. private 선언 후, 작성
private:
    using Base::print;

//방법 2. delete
private:
    void print() = delete;
11.9継承数
2つ以上のレベルを継承すること.
クラスAはクラスB、Cを継承し、BとCがgetID()の関数を有し、getID関数を呼び出す必要がある場合.
A a("test)";

a.B::getID();
a.C::getID(); 
これで呼びます.
以下の場合をダイヤモンド継承と呼びます.多重継承を誤って使用すると、次の問題が発生する可能性があります.

問題に対する解決法は多様な形で観察される.