Skip to content

Exam05: Polyset (Lv1)

C++におけるデータ構造の実装と、多重継承(ダイヤモンド継承)を用いたインターフェースの拡張を学ぶ課題です。

課題概要

「バッグ(Bag / Multiset)」とは、重複を許容するコレクションです。この課題では、配列と二分木を用いてバッグを実装し、さらに「検索機能(has)」を追加し、最終的に一意性を保証する「セット(Set)」ラッパーを作成します。

主要技術の深掘り

1. 仮想継承 (Virtual Inheritance)

searchable_bagbag を継承する際、および searchable_array_bag が両方を継承する際、bag の実体が重複しないように virtual public bag として継承する必要があります。

2. Set(ラッパー)

set クラスは継承階層には含まれず、searchable_bag の参照をメンバとして持ちます(Aggregation)。insert 時に has() で存在確認を行うことで、一意性を保証します。

ロジックの可視化

クラス図

この課題の核心は、ダイヤモンド継承(Diamond Inheritance)の理解と実装にあります。

コラム・読み物

モダンC++の設計思想や、技術的な詳細についての深掘り記事です。

よくある質問 (FAQ)

Q. has(), print() などをヘッダーに書いてもいい?

A. 短い転送関数(Forwarding function)やゲッターであれば、インライン化の恩恵を受けられるため推奨されます。ただし、複雑なロジックは .cpp に書くべきです。

Q. get_bag()const 版と非 const 版があるのはなぜ?

A. constset オブジェクトからは読み取り専用の bag を、変更可能な set オブジェクトからは変更可能な bag を返すためです。これにより const 正確性(Const Correctness)が保たれます。

Q. set の代入演算子はどうすべき?

A. set は参照(searchable_bag&)を持っていますが、参照先そのものを変えることはできません。代入演算子では、コピー元のバッグの中身をコピー先のバッグに反映させる(clear() して insert し直すなど)実装が一般的です。あるいは、代入を禁止(= delete)するのも一つの手です。

テストと検証 (main.cpp)

プログラムのエントリポイントとなる main.cpp は、以下の動作を確認するためのテストドライバです。

  1. 多態性: searchable_array_bagsearchable_tree_bag も、同じインターフェースで扱えること。
  2. 一意性: set ラッパー経由で挿入した場合、重複した値が無視されること。
  3. メモリ管理: valgrindLeaks でメモリリークがないこと。