0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】継承

Last updated at Posted at 2024-12-18

継承(※超重要)

用途 : 既存のクラス(基底クラス)を元に、新しいクラス(派生クラス)を定義
備考 : クラスの三大要素(カプセル化、継承、多態性)の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;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?