[C++]Chapter 07-継承について


07-1継承前
相続に関する問題を提起する案
まず、会社は正社員を管理するための計画を以下のように仮定します.
#include <iostream>
using namespace std;

class PermanentWorker
{
private:
	char name[100];
	int salary;
public:
	PermanentWorker(const char* name, int money) : salary(money)
	{
		strcpy(this->name, name);
	}
	int GetPay() const
	{
		return salary;
	}
	void ShowSalaryInfo() const
	{
		cout << "name: " << name << endl;
		cout << "salary: " << GetPay() << endl;
	}
};

class EmployeeHandler
{
private:
	PermanentWorker* empList[50];
	int empNum;
public:
	EmployeeHandler() : empNum(0)
	{}
	void AddEmployee(PermanentWorker* emp)
	{
		empList[empNum++] = emp;
	}
	void ShowAllSalaryInfo() const
	{
		for (int i = 0; i < empNum; i++)
			empList[i]->ShowSalaryInfo();
	}
	void ShowTotalSalary() const
	{
		int sum = 0;
		for (int i = 0; i < empNum; i++)
			sum += empList[i]->GetPay();
		cout << "salary sum: " << sum << endl;
	}
	~EmployeeHandler()
	{
		for (int i = 0; i < empNum; i++)
			delete empList[i];
	}
};

int main(void)
{
	EmployeeHandler handler;

	handler.AddEmployee(new PermanentWorker("KIM", 1000));
	handler.AddEmployee(new PermanentWorker("LEE", 1500));
	handler.AddEmployee(new PermanentWorker("JUN", 2000));

	handler.ShowAllSalaryInfo();

	handler.ShowTotalSalary();
	return 0;
}
しかし,これらのコードはプログラムの柔軟性と拡張性に欠けている.新しい雇用形態が現れたら、手続きを立て直さなければならないからだ.これらの問題は「継承」によって解決できます.
07-2継承構文の理解
関連サンプルの継承
#include <iostream>
#include <cstring>
using namespace std;

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

class UnivStudent : Person
{
private:
	char major[50];
public:
	UnivStudent(const char* myname, int myage, const char* mymajor) : Person(myage, myname)
	{
		strcpy(this->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;
}
この例は、UnivStudentクラスのPersonクラスのprivateメンバー変数が関数でアクセスでき、Personクラスで定義されたすべての共通関数が使用可能であることを示しています.C++では親Personをベースクラス,UnivStudioなどの子クラスをブートクラスと呼ぶことが多い.
誘導クラスのオブジェクトの作成
#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 ShowBaseData()
	{
		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()
	{
		ShowBaseData();
		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;
}
この例では、ブートクラスのオブジェクト作成中にベースクラスの作成者を呼び出し、ベースクラスの作成者呼び出しを指定しない場合、ベースクラスのvoid作成者を呼び出します.また、クラスのメンバーは、そのクラスの作成者によって初期化される必要があります.
クラス内のオブジェクトの消失を誘導するプロセス
#include <iostream>
using namespace std;

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

class SoDerived : public SoBase
{
private:
	int derivNum;
public:
	SoDerived(int n) : SoBase(n), derivNum(n)
	{
		cout << "SoDerived() : " << derivNum << endl;
	}
	~SoDerived()
	{
		cout << "~SoDerived() : " << derivNum << endl;
	}
};

int main(void)
{
	SoDerived drv1(15);
	SoDerived drv2(27);
	return 0;
}
たとえば、ブートクラスのオブジェクトが消滅すると、ブートクラスの消滅者が実行され、ベースクラスの消滅者が実行され、スタックで生成されたオブジェクトの消滅順序は生成順序とは逆になります.
これらの特性はまた、ジェネレータから動的に割り当てられたメモリ領域が破棄器から解放される原則に従って定義される必要があることを示しています.
07-3保護された宣言と3つの形式の継承
保護されたメンバーが許可するアクセス範囲として宣言
保護されている場合、privateと同様にクラスの外部からアクセスできませんが、クラスが継承されている場合は、継承されたクラスアクセスから保護されたメンバー変数として宣言できます.
class Base
{
private:
    int num1;
protected:
    int num2;
public:
    int num3;
}

class Derived : public Base
{
public:
    void ShowBaseMember()
    {
        cout << num1; // 컴파일 에러
        cout << num2; // 컴파일 OK
        cout << num3; // 컴파일 OK
    }
};
3つの継承
public、protected、privateがありますが、public以外の場合は、特別な場合でなければあまり使いにくいので、publicだけで十分です.
07-4継承条件
一般的には、IS-A関係の場合のみ継承されます.
ex)
  • 電話->ワイヤレス
  • コンピュータ->ノートパソコン
  • HAS−A関係も継承の条件であるが,通常は複合関係が用いられる.
    複合関係を表示するために個別のクラスを作成します.