いろいろなところであたかも簡単で特に難しいことがないように書かれているのを見るんですが、(というか自分もそう思ってたんですが)
実は難しいんじゃないか疑惑が自分の中で起こったのでメモしておきます。
まずインターフェースクラスですが、基本的にメンバ関数がすべて純粋仮想関数になっていてメンバ変数を持たないようなやつのことを言うようです
//---------IHogeBase.h----------
#pragma once
#include
#include
class IHogeBase{
public:
virtual ~IHogeBase(){};
virtual void PrintName() const = 0;
virtual void ResetName(const std::string& name) = 0;
protected:
IHogeBase(){}
IHogeBase(const IHogeBase&){}
IHogeBase& operator= (const IHogeBase&){}
};
std::shared_ptr CreateHogeBase(const std::string& name);
// -------CHogeBase.h-------------
#pragma once
#include "IHogeBase.h"
class CHogeBase:public IHogeBase{
public:
CHogeBase(const std::string& name):m_Name(name){}
void PrintName() const;
void ResetName(const std::string& name){
m_Name = name;
}
protected:
const std::string& GetName() const{
return m_Name;
}
private:
std::string m_Name;
};
//-----CHogeBase.cpp--------
#include "CHogeBase.h"
#include
void CHogeBase::PrintName() const{
std::cout CreateHogeBase(const std::string& name){
return std::shared_ptr(new CHogeBase(name));
}
で、問題はIHogeBaseを継承してIHogeDerivedを作るにはどうしたらいいか?という話に収束します。
ここで若干わからなくなりました。
まずインターフェース自体の継承は簡単です
//-------IHogeDerived.h----------
#pragma once
#include "IHogeBase.h"
class IHogeDerived:public IHogeBase{
public:
enum Type{
One = 1,
Two,
Three
};
public:
virtual ~IHogeDerived(){};
virtual void PrintName() const = 0;
virtual void ResetName(const std::string&) = 0;
virtual void PrintType() const = 0;
protected:
IHogeDerived(){}
IHogeDerived(const IHogeDerived&){}
IHogeDerived& operator=(const IHogeDerived&){}
};
std::shared_ptr CreateHogeDerived(const std::string& name, IHogeDerived::Type);
はい。
で、ここからなんですが、実装どうしたらいいんでしょう?
ええ、簡単な解決策はあります。
IHogeDerivedを継承してCHogeDerivedを作り、純粋仮想関数のすべてをオーバーライドして関数を定義すると。
でもはっきり言ってPrintNameの実装なんてのはCHogeBaseのものと同じで構わないわけです。
はーい、きました。コードの重複。
残念ながらIHogeDerivedを継承しただけではどう頑張ってもCHogeBaseのメンバは呼べないわけです。
どうしましょう?どうにも自分にはよくわかりません。何が正解なんでしょうね?
自分で考えた苦肉の策は、コンポジットパターンです
//-------CHogeDerived.h--------
#pragma once
#include "CHogeBase.h"
#include "IHogeDerived.h"
class CHogeDerived:
public IHogeDerived,private CHogeBase{
public:
CHogeDerived(const std::string& name, IHogeDerived::Type type):CHogeBase(name),m_Type(type){
}
void PrintName() const{
CHogeBase::PrintName();
}
void ResetName(const std::string& name){
CHogeBase::ResetName(name);
}
void PrintType() const;
private:
IHogeDerived::Type m_Type;
};
//--------CHogeDerived.cpp---------
#include "CHogeDerived.h"
#include
void CHogeDerived::PrintType() const {
std::cout CreateHogeDerived(const std::string& name, IHogeDerived::Type type){
return std::shared_ptr(new CHogeDerived(name, type));
}
これでとりあえず目的は果たしました。
//------main.cpp----------
#include "IHogeDerived.h"
void ChangeName(std::shared_ptr ptr, std::string& name){
ptr->ResetName(name);
ptr->PrintName();
}
int main(){
std::shared_ptr base = CreateHogeBase(std::string("Base"));
std::shared_ptr derived = CreateHogeDerived(std::string("Derived"), IHogeDerived::One);
base->PrintName();
ChangeName(base,std::string("Changed base"));
derived->PrintName();
ChangeName(derived, std::string("Changed derived"));
derived->PrintType();
return 0;
}
しかし、何とも不格好な気がしてならない・・・
もっといい解決策はないんですかね?