2018年02月02日
《その272》 抽象クラステンプレート
抽象クラステンプレート
下記のプログラムで、クラステンプレート Stack<> のメンバ関数は、すべて純粋仮想関数になっています。このような、クラステンプレートは抽象クラステンプレートと呼ばれ、具体性のない概念のみを定義しているため、この抽象クラステンプレートから直接 クラスオブジェクトを生成することはできません。
抽象クラステンプレートに具体性を持たせるのは、派生クラスの役目です。下記のプログラムでは、
抽象クラステンプレート Stack<> から public派生した ArrayStack<> が、「スタックを配列で実現する」という具体的なクラステンプレートになっています。
以下のプログラムでは、クラステンプレート ArrayStack<> を、ArrayStack<int> として利用し、整数値用のスタックを配列で実現しています。
#include <iostream>
// ------------------------------------
// 抽象クラステンプレート Stack<>
template <class Type> class Stack {
public:
class Overflow { }; // Overflow例外
class Empty { }; // Empty例外
// 純粋仮想デストラクタ
virtual ~Stack() = 0;
// 純粋仮想関数 push
virtual void push(const Type&) = 0;
// 純粋仮想関数 pop
virtual Type pop() = 0;
};
template <class Type>
Stack<Type>::~Stack() { }
// ------------------------------------
// クラステンプレート ArrayStack<>
template <class Type> class ArrayStack
: public Stack<Type> {
// データ収納用配列の要素数
static const int size = 6;
int ptr; // スタックポインタ
Type stk[size]; // スタックの本体
public:
ArrayStack() : ptr(0) { }
~ArrayStack() { }
void push(const Type& x) {
if (ptr >= size)
throw Stack<Type>::Overflow();
stk[ptr++] = x;
}
Type pop() {
if (ptr <= 0)
throw Stack<Type>::Empty();
return stk[--ptr];
}
};
// ------------------------------------
int main() {
ArrayStack<int> a;
try {
for (int i = 0; i < 6; i++)
a.push(100 + i);
}
catch (const Stack<int>::Overflow&) {
std::cout << "Overflow!\n";
}
try {
for (int i = 0; i < 6; i++)
std::cout << a.pop() << ' ';
std::cout << '\n';
}
catch (const Stack<int>::Empty&) {
std::cout << "Empty!\n";
}
Stack<int>* p1 = &a;
std::cout << "ポインタの型 : ";
std::cout << typeid(p1).name() << '\n';
std::cout << "オブジェクトの動的な型 : ";
std::cout << typeid(*p1).name() << '\n';
std::cout << "------------\n";
Stack<int>* p2 = new ArrayStack<int>();
try {
for (int i = 0; i < 6; i++)
p2->push(100 + i);
}
catch (const Stack<int>::Overflow&) {
std::cout << "Overflow!\n";
}
try {
for (int i = 0; i < 6; i++)
std::cout << p2->pop() << ' ';
std::cout << '\n';
}
catch (const Stack<int>::Empty&) {
std::cout << "Empty!\n";
}
std::cout << "ポインタの型 : ";
std::cout << typeid(p2).name() << '\n';
std::cout << "オブジェクトの動的な型 : ";
std::cout << typeid(*p2).name() << '\n';
delete p2;
}
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/7269427
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック