読者です 読者をやめる 読者になる 読者になる

貝柱が何かをする所

貝柱が何かをする所です、C++/Perl/その他諸々

継承先のクラスポインタを格納した親ポインタに適切なクラスを構築する

まえがき

今、SuperというクラスからAとBが派生しているとする。
C++では、Superのポインタには、継承関係にあるAのインスタンス、Bのインスタンスがそれぞれ格納できる。
例えば以下の様な感じだ

Super* ptr = new A();
Super* ptr2= new B();

では、格納しているインスタンスによって、新たに親クラスポインタに派生したクラスポインタを格納したい場合はどうすればよいのだろう?

Super* ptr = new A();  //ただし、場合によってはnew B()となりうる
Super* ptr2 = ???;  //ptrの内容にあわせてAかBのインスタンスを格納したい

今回はこれを実現する

アプローチ

クラスが親子関係にあり、親クラスのメソッドを子クラスが継承したとする。
例えば、Superにshow()なるメソッドがあり、子クラスがそれを継承しているとすると、
次のコードでは

Super* ptr = new A();
ptr->show();

Superのshow()ではなく、Aのshow()が呼ばれる。これは多態性と呼ばれる特性によるものだ。

これを使い、自分自身のインスタンスを作成し返すファクトリ関数のようなものを持つことで、主題の問題を解決する

コード
#include <iostream>
#include <memory>

struct Super {
	virtual void show() {
		std::cout << "I am Super" << std::endl;
	}
	virtual std::unique_ptr<Super> make_me() = 0;
};

struct A : public Super {
	void show() override {
		std::cout << "I am A" << std::endl;
	}
	std::unique_ptr<Super> make_me() override {
		return std::unique_ptr<Super>(new A());
	}
};

struct B : public Super {
	void show() override {
		std::cout << "I am B" << std::endl;
	}
	std::unique_ptr<Super> make_me() override {
		return std::unique_ptr<Super>(new B());
	}
};

int main(void) {
	std::unique_ptr<Super> ptr_A = std::make_unique<A>();
	std::unique_ptr<Super> ptr_B = std::make_unique<B>();

	std::unique_ptr<Super> ptr_g = ptr_A->make_me();
	ptr_g->show();    // I am A
	ptr_g.reset();

	ptr_g = ptr_B->make_me();
	ptr_g->show();    // I am B

	return 0;
}