継承(※超重要)
用途 : 既存のクラス(基底クラス
)を元に、新しいクラス(派生クラス
)を定義
備考 : クラスの三大要素(カプセル化、継承、多態性)の1つ。
主に継承を使っていい場合は以下の2つ
Is-A の関係 : 動物(基底クラス) is 犬(派生クラス)
Has-A の関係 : 犬(基底クラス) has 心臓(派生クラス)
Animal.h
#ifndef ANIMAL_H_INCLUDED
#define ANIMAL_H_INCLUDED
#include <iostream>
/// <summary>
/// 基底クラス
/// </summary>
class Animal
{
public:
/// <summary>
/// デフォルトコンストラクタ
/// </summary>
Animal()
{
countLick = 5;
std::cout << "アニマルクラスのコンストラクタ呼び出し" << std::endl;
}
/// <summary>
/// デストラクタ
/// </summary>
~Animal()
{
std::cout << "アニマルクラスのデストラクタ呼び出し" << std::endl;
}
void Lick(void)
{
std::cout << "動物が舐めてきた!!" << std::endl;
}
int countLick; // 舐めた回数
};
#endif // !ANIMAL_H_INCLUDED
Dog.h
#ifndef DOG_H_INCLUDED
#define DOG_H_INCLUDED
#include "Animal.h"
#include <format>
/// <summary>
/// 基底クラス
/// </summary>
class Dog
: public Animal
{
public:
/// <summary>
/// デフォルトコンストラクタ
/// </summary>
Dog()
{
std::cout << "ドッグクラスのコンストラクタ呼び出し" << std::endl;
}
/// <summary>
/// デストラクタ
/// </summary>
~Dog()
{
std::cout << "ドッグクラスのデストラクタ呼び出し" << std::endl;
}
void Lick(void)
{
std::cout << std::format("犬が{}回舐めてきた!!", countLick) << std::endl;
}
};
#endif // !DOG_H_INCLUDED
example.cpp
#include "Dog.h"
int main()
{
{
// アニマルクラスのインスタンスを生成
Animal animal;
animal.Lick();
}
std::cout << std::endl;
{
// ドッグクラスのインスタンスを生成
Dog dog;
dog.Lick();
}
return 0;
}
アクセス指定子
public(公開継承) : 派生クラスにそのまま継承
private(非公開継承) : 派生クラスへ全てが非公開で継承
C++の標準ライブラリを開発するような人以外は、publicしか使いません(笑)
アップキャストとダウンキャスト(C++)
アップキャスト : 基底クラスのポインタに派生クラスを格納
ダウンキャスト : 派生クラスのポインタに基底クラスを格納
※ダウンキャストは使用禁止
example.cpp
#include "Dog.h"
int main()
{
{
// アニマルクラスのポインタに
// アニマルクラスのインスタンスを生成
Animal* animal = new Animal();
animal->Lick();
delete animal;
}
std::cout << std::endl;
{
// アニマルクラスのポインタに
// ドッグクラスのインスタンスを生成
Animal* dog = new Dog();
dog->Lick();
delete dog;
}
return 0;
}
ドッグクラスのデストラクタが呼ばれていない...
仮想関数
用途 : 基底クラスの関数を、派生クラスで上書き(オーバーライド
)することを可能にする
Animal.h
#ifndef ANIMAL_H_INCLUDED
#define ANIMAL_H_INCLUDED
#include <iostream>
/// <summary>
/// 基底クラス
/// </summary>
class Animal
{
public:
/// <summary>
/// デフォルトコンストラクタ
/// </summary>
Animal()
{
countLick = 5;
std::cout << "アニマルクラスのコンストラクタ呼び出し" << std::endl;
}
/// <summary>
/// デストラクタ
/// </summary>
virtual ~Animal()
{
std::cout << "アニマルクラスのデストラクタ呼び出し" << std::endl;
}
virtual void Lick(void)
{
std::cout << "動物が舐めてきた!!" << std::endl;
}
int countLick; // 舐めた回数
};
#endif // !ANIMAL_H_INCLUDED
オーバーライド
オーバーライドは、基底クラスの仮想関数を継承し、上書きしたことを明示的にする
Dog.h
#ifndef DOG_H_INCLUDED
#define DOG_H_INCLUDED
#include "Animal.h"
#include <format>
/// <summary>
/// 基底クラス
/// </summary>
class Dog
: public Animal
{
public:
/// <summary>
/// デフォルトコンストラクタ
/// </summary>
Dog()
{
std::cout << "ドッグクラスのコンストラクタ呼び出し" << std::endl;
}
/// <summary>
/// デストラクタ
/// </summary>
virtual ~Dog()
{
std::cout << "ドッグクラスのデストラクタ呼び出し" << std::endl;
}
virtual void Lick(void) override
{
std::cout << std::format("犬が{}回舐めてきた!!", countLick) << std::endl;
}
};
#endif // !DOG_H_INCLUDED
純粋仮想関数
用途 : 継承先で純粋仮想関数のオーバーライドを強制させる
- 備考
実装がなくプロトタイプ宣言のみ
また、純粋仮想関数を実装したクラスは抽象クラスになる(=インスタンス化不可)
Animal.h
#ifndef ANIMAL_H_INCLUDED
#define ANIMAL_H_INCLUDED
#include <iostream>
/// <summary>
/// 基底クラス
/// </summary>
class Animal
{
public:
/// <summary>
/// デフォルトコンストラクタ
/// </summary>
Animal()
{
countLick = 5;
std::cout << "アニマルクラスのコンストラクタ呼び出し" << std::endl;
}
/// <summary>
/// デストラクタ
/// </summary>
virtual ~Animal()
{
std::cout << "アニマルクラスのデストラクタ呼び出し" << std::endl;
}
// 純粋仮想関数
virtual void Lick(void) = 0;
int countLick; // 舐めた回数
};
#endif // !ANIMAL_H_INCLUDED
example.cpp
#include "Dog.h"
int main()
{
// アニマルクラスのポインタに
// ドッグクラスのインスタンスを生成
Animal* dog = new Dog();
dog->Lick();
delete dog;
return 0;
}
※C#では、=0は必要なし
多態性(※超重要)
多態性とは、同名のメンバ関数が、異なる状況下で異なる処理を行うこと。
備考 : クラスの三大要素(カプセル化、継承、多態性)の1つ。
#include <iostream>
class Animal
{
public:
Animal() {}
virtual ~Animal() {}
virtual void Voice(void) = 0;
};
class Dog
: public Animal
{
public:
Dog() {}
virtual ~Dog() {}
virtual void Voice(void) override
{
std::cout << "ワンワン" << std::endl;
}
};
class Cat
: public Animal
{
public:
Cat() {}
virtual ~Cat() {}
virtual void Voice(void) override
{
std::cout << "ニャーニャー" << std::endl;
}
};
int main()
{
{
Animal* dog = new Dog();
dog->Voice();
delete dog;
}
std::cout << std::endl;
{
Animal* cat = new Cat();
cat->Voice();
delete cat;
}
return 0;
}