私の質問の最も簡単な例では、次のコードスニペットで見ることができます。派生クラスへのポインタと同時にベースクラスへの参照をインスタンス化できないのはなぜですか?
ここclass Handle : public IHandle_<Handle>{
public:
Handle(std::unique_ptr<Derived> aDerived)
: derived(std::move(aDerived)),
base(*aDerived) {};
std::unique_ptr<Derived> derived;
Base& base;
};
、あなたはHandle
クラスは、基本的にDerived
のラッパーであることがわかります。さらに重要なことは、基底クラスDerived
、Base
を参照として公開したいと考えています。
class Handle : public IHandle_<Handle>{
private:
std::unique_ptr<Derived1> myD1;
std::unique_ptr<Derived2> myD2;
public:
Handle(std::unique_ptr<Derived1> aD1)
: myD1(std::move(aD1)),
base1(*aD1),
base2(*aD1){};
Handle(std::unique_ptr<Derived2> aD2)
: myD2(std::move(aD2)),
base1(*aD2),
base2(*aD2){};
Base1& base1;
Base2& base2;
};
私はこのように動作するようにHandle
を望む理由は、私が "中「コンポーネント」としてそれを使用していますということである。この理由は、最終的に、私はこのような何かを見てHandle
を望む、ということですエンティティコンポーネントシステム 'と呼ばれ、この特定のコンポーネントが同じ2つの基本クラスの2つの異なる具体的な実装からインスタンス化可能であることを希望します。私はこれを言及します。なぜなら、エンティティコンポーネントシステムのデザインパターンは、定義上、伝統的なオブジェクト指向プログラミングの慣行から逸脱しているからです。言い換えれば、私がやろうとしていることを達成するための他の方法があると知っています。私がここに挙げたもののいくつかのバリエーション。
質問
なぜ私の最初のスニペットに示す簡単なHandle
の例では、失敗しませんか? Base
のメソッドにアクセスしようとすると、うまくコンパイルされますが、segフォルトがコンパイルされます。私がHandle
というメンバ変数をインスタンス化する順序を変更すると、コンパイル時にいくつかのヒントが出ると思うが、何が起こっているのか分かりません。ここで
はHandle
の完全な実施例と、それが依存するクラスです:
#include <memory>
#include <iostream>
class Base{
public:
Base(int ax) : x(ax){};
virtual ~Base() = 0;
virtual void setVal(float a) = 0;
virtual float getVal() = 0 ;
int x;
};
Base::~Base(){}
class Derived : public Base{
public:
Derived(int ax, int az)
: Base(ax), z(az){};
int z;
};
class Concrete : public Derived{
public:
Concrete(int ax, int aw, int av)
: Derived(ax, aw),
v(av){};
void setVal(float a) override{
myVal = a;
}
float getVal() override{
return myVal;
}
float myVal;
int v;
};
class IHandle{
public:
virtual ~IHandle() = 0;
};
IHandle::~IHandle(){}
template <class T>
class IHandle_ : public IHandle{
public:
virtual ~IHandle_() = 0;
};
template <class T>
IHandle_<T>::~IHandle_(){};
class Handle : public IHandle_<Handle>{
public:
Handle(std::unique_ptr<Derived> aDerived)
: derived(std::move(aDerived)),
base(*aDerived) {};
std::unique_ptr<Derived> derived;
Base& base;
};
int main(){
// These two pointers are owned by an EntityManager
std::unique_ptr<Derived> ptr(new Concrete(1, 2, 3));
// we can get a reference to an IHandle from the EntityManager
std::unique_ptr<IHandle> aHandle(new Handle(std::move(ptr)));
// We need, specifically, a `Handle` implementation of `IHandle`
Handle& handle = static_cast<Handle&>(*aHandle);
// seg fault on the following line
handle.base.setVal(10.0);
std::cout << "a = " << handle.base.getVal() << std::endl;
return 0;
}
を持っています。 – Yakk
私は "なぜ"を提供すると思います。しかし、あなたのコメントに続いて、絶対に合理的です:@wesanyer、ベースクラスの参照の必要性は何ですか?なぜあなたの文脈でそれを必要としますか? –