c++ - Why can't I instantiate a reference to a base class at the same time as a pointer to a derived class? -
the simplest example of question can seen in following code snippet:
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; };
here, can see handle
class wrapper around derived
. more importantly, wish expose base class of derived
, base
, way of reference. reason that, ultimately, wish handle
this:
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; };
the reason wish handle
work using 'component' in 'entity component system', , i'd particular component instantiatable 2 different concrete implementations of same 2 base classes. mention because 'entity component system' design pattern definition departs traditional object-oriented programming practices: in other words, know there other ways of accomplishing trying do, wish make work in variation of have listed here.
question
why simple handle
example shown in first snippet fail? compiles fine seg-faults when trying access method in base
. if change order in instantiate member variables of handle
, errors @ compile time think provide hints not understand going on.
here full working example of handle
, classes depends on:
#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 2 pointers owned entitymanager std::unique_ptr<derived> ptr(new concrete(1, 2, 3)); // can reference ihandle entitymanager std::unique_ptr<ihandle> ahandle(new handle(std::move(ptr))); // need, specifically, `handle` implementation of `ihandle` handle& handle = static_cast<handle&>(*ahandle); // seg fault on following line handle.base.setval(10.0); std::cout << "a = " << handle.base.getval() << std::endl; return 0; }
the members in c++ class initialized in order declare them, looking @ first snippet, order of initialization of members in handle class is:
- derived
- base
that said, means in constructor line
derived(std::move(aderived))
will transfer internal resources of aderived
derived
, reasonably resetting state of aderived
. code reach statement
base(*aderived)
base
reference empty (depends on move constructor implementation inside base , derived class) object deleted memory after call of constructor itself.
so, believe reference base
got in code pointing not allocated memory, giving seg_fault error.
seg_fault of time refers code using (in case writing, see setval() ) area of memory not (yet or anymore) allocated running process.
hope may help, have night, stefano
Comments
Post a Comment