抽象クラス
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 60/104。
abstract class とは、少なくとも 1 つの純粋仮想 function を含む class です。不完全なインターフェースを持つため、abstract class のオブジェクトを直接作成することは cannot であり、継承されるためだけに存在します。
class Shape {
public:
virtual double area() = 0; // 純粋仮想 - Shapeを抽象にする
virtual double perimeter() = 0; // 別の純粋仮想関数
void printInfo() { // 通常のメソッド - 実装がある
std::cout << "Area: " << area() << std::endl;
}
virtual ~Shape() = default;
};
Shape s; // エラー: 抽象クラスをインスタンス化できない抽象クラスには、純粋仮想関数(実装なし)、通常の仮想関数(デフォルト実装あり)、および非仮想関数を組み合わせて含めることができます。これにより、共通の動作を定義しながら、派生クラスに特定の機能の実装を要求できます。
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() override { return 3.14159 * radius * radius; }
double perimeter() override { return 2 * 3.14159 * radius; }
};
Circle c(5.0); // OK: Circle はすべての純粋仮想関数を実装しています
c.printInfo(); // 継承された printInfo() を使用し、Circle の area() を呼び出します派生クラスが具象(インスタンス化可能)になるには、すべての純粋仮想関数を実装する必要があります。未実装のものを残すと、そのクラス自体が abstract のままになります。この仕組みにより、階層内のすべての具象クラスが必要な機能を提供することが保証されます。
チャレンジ
簡単異なるメディアタイプに対して abstract クラスがどのように契約を定義するかを示すメディアプレーヤーシステムを構築しましょう。すべてのメディアプレーヤーが実行すべき内容を定める abstract な基底クラスを作成し、その後、音声および動画コンテンツ用の具象プレーヤーを実装します。
コードを3つのファイルに分けて整理します。
MediaPlayer.h:すべてのメディアタイプの設計図となる abstract なMediaPlayerクラスを定義します。abstract クラスには、次の要素を含めます。- protected な
std::string titleメンバー - protected な
int durationメンバー(秒単位) - 両方の値を初期化する constructor
- pure virtual の
play()メソッド:各メディアタイプは異なる方法で再生します std::stringを返す pure virtual のgetMediaType()メソッド<title> (<duration>s) - Type: <mediaType>を出力する通常の(virtual ではない)showInfo()メソッド。このメソッドでは、タイプを取得するためにgetMediaType()を呼び出します- virtual destructor
- protected な
Players.h:MediaPlayerを継承する2つの具象メディアプレーヤーを実装します。AudioPlayer:- private な
std::string artistメンバー - title、duration、artist を受け取る constructor
play()を実装し、Playing audio: <title> by <artist>を出力しますgetMediaType()を実装し、"Audio"を返します
VideoPlayer:- private な
std::string resolutionメンバー - title、duration、resolution を受け取る constructor
play()を実装し、Playing video: <title> in <resolution>を出力しますgetMediaType()を実装し、"Video"を返します
- private な
main.cpp:4つの入力を読み取ります(それぞれ別の行に入力されます)。- 音声トラックのタイトル
- 音声の duration(整数)
- 動画のタイトル
- 動画の duration(整数)
artist に
"Unknown Artist"を指定したAudioPlayerと、resolution に"1080p"を指定したVideoPlayerを作成します。両方をMediaPlayer*ポインターの配列に格納します。配列をループし、各プレーヤーについて、まず
showInfo()を呼び出し、その後play()を呼び出します。各メディア項目の間には空行を出力します。処理が完了したら、dynamically allocated されたオブジェクトを Clean up します。
たとえば、入力が Summer Vibes、180、Nature Documentary、3600 の場合:
Summer Vibes (180s) - Type: Audio
Playing audio: Summer Vibes by Unknown Artist
Nature Documentary (3600s) - Type: Video
Playing video: Nature Documentary in 1080pshowInfo() メソッドは abstract な基底クラスで一度だけ定義されていますが、pure virtual の getMediaType() を呼び出している点に注目してください。これは、abstract クラスが具象的な実装と、Derived クラスが提供しなければならないメソッドを組み合わせられることを示しています。オーバーライドするすべてのメソッドで override キーワードを使用することを忘れないでください。
自分で試してみよう
#include <iostream>
#include <string>
#include "MediaPlayer.h"
#include "Players.h"
int main() {
// 入力を読み取る
std::string audioTitle;
int audioDuration;
std::string videoTitle;
int videoDuration;
std::getline(std::cin, audioTitle);
std::cin >> audioDuration;
std::cin.ignore();
std::getline(std::cin, videoTitle);
std::cin >> videoDuration;
// TODO: アーティスト "Unknown Artist" の AudioPlayer を作成する
// TODO: 解像度 "1080p" の VideoPlayer を作成する
// TODO: 両方を MediaPlayer* ポインタの配列に格納する
// TODO: 配列をループして各プレイヤーについて:
// 1. showInfo() を呼び出す
// 2. play() を呼び出す
// 3. 各メディアアイテムの間に空行を出力する
// TODO: 動的に割り当てられたオブジェクトをクリーンアップする
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ