C++ (Qt)struct CData { int mID; QString mName; .. AbstractClass * mData;};
AbstractClass * mData;
wrapper<AbstractClass> mData;
{ // example// AbstractClass может не иметь clone, // и не иметь виртуального деструктора.// но если он хочет клонироваться - наследники // должны иметь конструктор копии явный, или дефолтныйwrapper<AbstractClass> obj1; // захват ресурса // создается конкретный наследник// некоторые реализации при этом не используют кучу// params соответствует аргументам конструктораobj1.make<Concrete>(params); // операция клонирования реализована в самом wrapper// нет нужды переопределять виртуальные методы в каждом наследнике// при помощи паттерна type erasure// враппер "запомнил" тип ресурса, который он захватил// поэтому, он может звать конструкторы/диструкторы/прочие методы// наследника напрямки, минуя его базовый интерфейсwrapper<AbstractClass> obj2 = obj1.clone(); } // example// вот здесь время жизни врапперов завершилось// и они ликвидировали свои ресурсы,// вызвав диструкторы самих наследников// поэтому очистка будет корректна// даже если диструктор базового класса - не виртуальный
#include <iostream>#include <memory>struct base{ base() { std::cout<<"base: ctor\n"; } // ничайно забыли сделать его виртуальным ~base() { std::cout<<"base: dtor\n"; } virtual void foo()const = 0; };struct der: base{ der() { std::cout<<"der: ctor\n"; } // TODO: внимание! формально, здесь потенциальное UB // только для ознакомления! // стандарт требует наличие виртуального диструктора // в базовом интерфейсе, если предполагается использовать полиморфизм ~der() { std::cout<<"der: dtor\n"; } virtual void foo()const {std::cout<<"der: foo\n"; } };int main(){ std::cout << "Hello, world!\n"; { // ничего ни о каких наследниках не знает using wrapper = std::shared_ptr<base>; // зато про наследника знает функция захвата ресурса wrapper obj1 = std::make_shared<der>(); // она построит особую разновидность wrapper // внутри которого будет внедрен helper, // реализуюющий type erasure // он будет "помнить" настоящий тип ресурса // и при самоуничтожении // позовет корректный диструктор напрямки // минуя базовый интерфейс } // вот здесь мы увидим корректный запуск диструктора наследника std::cout << "Finish\n";}
C++ (Qt)#include <iostream>#include <memory> struct CBase { CBase( void ) { std::cout << "Consruct Base\n"; } ~CBase( void ) { std::cout << "Destruct Base\n"; } virtual const char * Name( void ) { return "Base"; } // data int mA;}; struct CDerived : public CBase { CDerived( void ) { std::cout << "Consruct Derived\n"; } ~CDerived( void ) { std::cout << "Destruct Derived\n"; } virtual const char * Name( void ) { return "Derived"; } // data int mB;}; template <class T>struct CWrapper { CWrapper( void ) { mData = malloc(sizeof(T)); new (mData) T; } ~CWrapper( void ) { Destroy(); } T * data( void ) { return (T *) mData; } const T * data( void ) const { return (T *) mData; } template <class T2> void Init( void ) { Destroy(); mData = malloc(sizeof(T2)); new (mData) T2; } virtual void Destroy( void ) { if (mData) { delete (T *) mData; mData = 0; } } template <class T2> CWrapper & operator = ( const CWrapper<T2> & src ) { Destroy(); mData = malloc(sizeof(T2)); new (mData) T2(*src.data()); return *this; } private: // data void * mData;}; int main(int argc, char *argv[]){ CWrapper<CBase> wrap1; CWrapper<CDerived> wrap2; std::cout << "\nTest1\n\n"; std::cout << "wrap1 = " << wrap1.data()->Name() << " wrap2 = " << wrap2.data()->Name() << std::endl; wrap1 = wrap2; std::cout << "wrap1 = " << wrap1.data()->Name() << " wrap2 = " << wrap2.data()->Name() << std::endl; std::cout << "\nTest2\n\n"; CWrapper<CBase> wrap3; std::cout << "wrap3 = " << wrap3.data()->Name() << std::endl; wrap3.Init<CDerived>(); std::cout << "wrap3 = " << wrap3.data()->Name() << std::endl; return 0;}
C++ (Qt)Ну хрен с ней, давай психическую...
C++ (Qt)#include <iostream> //------------------------ CDeepPointer --------------------------------- template <class T>struct CDeepPointer { struct CControl; struct CData; template<class T2> struct CDataStorage; template<class T2> struct CTypedControl; CDeepPointer( void ) { CTypedControl<T>().create(mData, 0); } ~CDeepPointer( void ) { reset(); } T * data( void ) { return (T *) mData.mPtr; } const T * data( void ) const { return (T *) mData.mPtr; } bool isNull( void ) const { return !mData.mPtr; } T * operator -> ( void ) { return data(); } template <class T2> void set( const T2 * src = 0 ) { reset(); CTypedControl<T2>().create(mData, src); } void reset( void ) { if (mData.mCtl) mData.mCtl->destroy(mData); } CDeepPointer & operator = ( const CDeepPointer<T> & src ) { reset(); if (src.mData.mCtl) src.mData.mCtl->create(mData, src.mData.mPtr); return *this; } template <class T2> CDeepPointer & operator = ( const CDeepPointer<T2> & src ) { reset(); if (src.mCtl) src.mCtl->create(mData, src.mData.mPtr); return *this; } struct CData { void * mPtr; CControl * mCtl; }; template<class T2> struct CDataStorage { CDataStorage( void ) {} CDataStorage( const T2 * src ) : mData(*src) {} // data members T2 mData; CTypedControl<T2> mCtl; }; struct CControl { virtual void create( CData & data, const void * src ) const = 0; virtual void destroy( CData & data) const = 0; }; template <class T2> struct CTypedControl : public CControl { virtual void create( CData & data, const void * src ) const { CDataStorage<T2> * storage = 0; if (src) storage = new CDataStorage<T2>((T2 *) src); else storage = new CDataStorage<T2>; data.mPtr = storage; data.mCtl = &storage->mCtl; } virtual void destroy( CData & data ) const { delete (CDataStorage<T2> *) data.mPtr; data.mPtr = 0; data.mCtl = 0; } }; private: CData mData;}; //------------------------ Test Classes ----------------------------- struct CBase { CBase( void ) { std::cout << "Consruct Base\n"; } ~CBase( void ) { std::cout << "Destruct Base\n"; } virtual const char * Name( void ) { return "Base"; } // data int mA;}; struct CDerived : public CBase { CDerived( void ) { std::cout << "Consruct Derived\n"; } ~CDerived( void ) { std::cout << "Destruct Derived\n"; } virtual const char * Name( void ) { return "Derived"; } // data int mB;}; //------------------------ main ----------------------------- int main(int argc, char *argv[]){ CDeepPointer<CBase> ptr1, ptr2; ptr2.set<CDerived>(); std::cout << "\nTest1\n\n"; std::cout << "ptr1 = " << ptr1->Name() << " ptr2 = " << ptr2->Name() << std::endl; ptr1 = ptr2; std::cout << "ptr1 = " << ptr1->Name() << " ptr2 = " << ptr2->Name() << std::endl; std::cout << "\nTest2\n\n"; ptr1.reset(); return 0;}
C++ (Qt)#include <iostream>#include <string>#include <sstream> //------------------------ CDeepPointer --------------------------------- template <class T>struct CDeepPointer { struct CControl; template<class T2> struct CTypedControl; CDeepPointer( void ) : mPtr(0), mCtl(0) { } template<class T2> CDeepPointer( T2 * src ) : mPtr(src), mCtl(0) { if (mPtr) mCtl = new (mPlace) CTypedControl<T2>(); } ~CDeepPointer( void ) { reset(); } T * data( void ) { return (T *) mPtr; } const T * data ( void ) const { return (T *) mPtr; } bool isNull ( void ) const { return !mPtr; } T * operator -> ( void ) { return data(); } T & operator * ( void ) { return *data(); } bool operator ! ( void ) const { return isNull(); } operator bool ( void ) const { return !isNull(); } template <class T2> void reset( T2 * src ) { if (data() == TypeCheck(src)) return; reset(); mPtr = src; mCtl = new (mPlace) CTypedControl<T2>(); } void reset( void ) { if (mCtl) { mCtl->destroy(mPtr); mPtr = 0; mCtl = 0; } } CDeepPointer & operator = ( const CDeepPointer & src ) { return operator = <T>(src); } template <class T2> CDeepPointer & operator = ( const CDeepPointer<T2> & src ) { if (data() == TypeCheck(src.data())) return *this; reset(); if (src.control()) mPtr = src.control()->create(src.data(), mPlace); return *this; } CControl * control( void ) const { return mCtl; } template<class T2> const T * TypeCheck( const T2 * src ) { return src; } struct CControl { virtual void * create( const void * src, void * place ) const = 0; virtual void destroy( void * data) const = 0; }; template <class T2> struct CTypedControl : public CControl { virtual void * create( const void * src, void * place ) const { new (place) CTypedControl<T2>; return src ? new T2(*(T2 *) src) : new T2; } virtual void destroy( void * data ) const { delete (T2 *) data; } }; private: void * mPtr; CControl * mCtl; char mPlace[sizeof(CTypedControl<T>) * 2];}; //------------------------ Test Classes ----------------------------- struct CBase { CBase( int a = 0 ) : mA(a) { std::cout << "Consruct Base\n"; } // Note: destructor is non-virtualintentionally, for test purposes ~CBase( void ) { std::cout << "Destruct Base\n"; } virtual std::string toString( void ) { std::stringstream strm; strm << "Base(" << mA << ")"; return strm.str(); } // data int mA;}; struct CDerived : public CBase { CDerived( int a = 0, int b = 0 ) : CBase(a), mB(b) { std::cout << "Consruct Derived\n"; } ~CDerived( void ) { std::cout << "Destruct Derived\n"; } virtual std::string toString( void ) { std::stringstream strm; strm << "Derived(" << mA << "," << mB << ")"; return strm.str(); } // data int mB;}; //------------------------ main ----------------------------- int main( int argc, char *argv[] ){ CDeepPointer<CBase> ptr1(new CBase(1)); CDeepPointer<CBase> ptr2(new CDerived(2, 3)); std::cout << "\nTest1\n\n"; std::cout << "ptr1 = " << ptr1->toString() << " ptr2 = " << ptr2->toString() << std::endl; ptr1 = ptr2; std::cout << "ptr1 = " << ptr1->toString() << " ptr2 = " << ptr2->toString() << std::endl; std::cout << "\nTest2\n\n"; ptr2.reset(); return 0;}