A subclass of the class that inherits from enable_shared_from_this, which returns shared_ptr

I am wondering if there is something like this pseudocode:

class A : public std::enable_shared_from_this<A> {
    public:
        std::shared_ptr<self_t> getPtr(){
            return std::static_pointer_cast<self_t>(shared_from_this());
        }
};

class B : public A {
    std::vector<A> container;

    std::shared_ptr<self_t> addChild(A child){
        container.push_back(child);
        return getPtr();
    }
};

class C : public B {
    public:
        std::shared_ptr<self_t> doSomething(){
            // something
            return getPtr();
        }
};

int main(){
    A obja = new A();
    C obj = new C();
    obj->addChild(obja)->doSomething()
}

My goal is that an object represents a view (both in V in MVC) and so that methods can return for a chained call. For example: ->setTop(0)->addChild(child1)->setBottom(0).

I read that it might be more affordable to do something like operator overloading <<, but I don’t see it working well or looking very pretty.

It seemed to me that I had to make a macro with a name VIEW(name,parent)that would use templates for extension, but I had a problem with the default self-refferental template arguments.

Any help would be greatly appreciated.

- change -

enable_shared_from_this. , doSomething, . , , doSomething . doSomething .

+4
4

, , , ... #, ++. # :

// c# syntax
namespace MyBaseExtensions {
    public static class MyBaseExt {
        public static shared_ptr<T> getPtr<T>(this T self) where T : MyBase 
        {
            return static_pointer_cast<T>(self.shared_from_this());
        }
    }
}

, MyBase , , .

, . , :

int main(){
    A obja = new A();
    C obj = new C();
    obj->getPtr()->addChild(obja)->doSomething()
}

int main(){
    A obja = new A();
    C obj = new C();
    doSomething(addChild(getPtr(obj),obja)); //eyeroll.
}

,

// C++ syntax
namespace MyBaseExtensions {
    template<typename T> std::shared_ptr<T> getPtr<T>(T self)
    {
        return std::static_pointer_cast<T>(self->shared_from_this());
    }
}

, . , , , , , ( ). ++ , , .

.

, :

#include <vector>
#include <memory>

// 0 argument, creates an overload method (and hides parent class method)
//           from template method func_name
// template method specialization of a parent method does not work
//      so we use C++11 automatic type deduction to figure the      
//         template return type and return what the template returns
#define FUNC_DEF_0(base, cur, func_name) \
    auto func_name() \
            -> decltype(base().func_name<cur>()) { \
        return base::func_name<cur>(); \
    }

// 1 argument
#define FUNC_DEF_1(base, cur, func_name, arg1_t) \
    auto func_name(arg1_t param1) \
            -> decltype(base().func_name<cur>(param1)) { \
        return base::func_name<cur>(param1); \
    }

// class A
// add to class to hide class A methods
#define HIDE_A(current) \
    FUNC_DEF_0(A, current, getPtr)

class A : public std::enable_shared_from_this<A> {
public:
    template<typename _T = A>
    std::shared_ptr<_T> getPtr(){
        return std::static_pointer_cast<_T>(shared_from_this());
    }
};


// class B
// add to class to hide class B methods with new methods
#define HIDE_B(current) \
    HIDE_A(current) \
    FUNC_DEF_1(B, current, addChild, A)

class B : public A {
public:
    std::vector<A> container;

    template<typename _T = B>
    std::shared_ptr<_T> addChild(A child){
        container.push_back(child);
        return A::getPtr<_T>();
    }

    HIDE_A(B); // hide A methods with B specialized methods

    // Example method hiding
    // auto getPtr() -> decltype(A().getPtr<B>()) {
    //     return base::getPtr<B>();
    // }
};


// class C
// add to class to hide class C methods
#define HIDE_C(current) \
    HIDE_B(current) \
    FUNC_DEF_0(C, current, doSomething)

class C : public B {
public:
    template<typename _T = C>
    std::shared_ptr<_T> doSomething(){
        // something
        return A::getPtr<_T>();
    }
    HIDE_B(C); // hide B methods
};

int main() {
    auto obja = std::make_shared<A>();
    auto obj = std::make_shared<C>();
    obj->addChild(*obja)->doSomething();
}

: ​​. .

class A;

struct virtual_enable_shared_from_this_base :
    std::enable_shared_from_this<virtual_enable_shared_from_this_base> {
    virtual ~virtual_enable_shared_from_this_base() {}
};

#define HIDE_AMix(type) \
    using type::getPtr;

template<typename _T>
class AMix : public virtual virtual_enable_shared_from_this_base {
public:
    std::shared_ptr<_T> getPtr() {
        auto sptr = shared_from_this();
        return std::dynamic_pointer_cast<_T>(sptr);
    }
};

#define HIDE_BMix(type) \
    HIDE_AMix(type) \
    using type::addChild;

template<typename _T>
class BMix : public AMix<_T>{
public:
    std::vector<std::shared_ptr<A>> container;

    std::shared_ptr<_T> addChild(A* child){
        container.push_back(child->getPtr());
        return getPtr();
    }
};

#define HIDE_CMix(type) \
    HIDE_BMix(type) \
    using type::addChild;

template<typename _T>
class CMix : public BMix<_T>{
public:
    std::shared_ptr<_T> doSomething(){
        // something
        return getPtr();
    }
};


class A : public AMix<A> {
public:

};

class B : public A, public BMix<B> {
public:
    HIDE_AMix(BMix<B>);
    //using BMix<B>::getPtr;
    //using BMix<B>::addChild;
};

class C : public B, public CMix<C> {
public:
    HIDE_BMix(CMix<C>);
    //using CMix<C>::getPtr;
    //using CMix<C>::addChild;
    //using CMix<C>::doSomething;
};

int main() {
    auto obja = std::make_shared<B>();
    auto obj = std::make_shared<C>();
    obja->getPtr();
    obj->addChild(obja.get())->doSomething();
}

Edit2: .

+1

, , , ( , 100% ). , ...

#include <iostream>
#include <memory>
#include <vector>

class MyBase;
typedef std::shared_ptr<MyBase> MyBaseSharedPtr;

class MyBase : public std::enable_shared_from_this<MyBase> {
        public:
                MyBaseSharedPtr getPtr() { return shared_from_this(); }
                virtual MyBaseSharedPtr doSomething() { return getPtr(); };
                virtual MyBaseSharedPtr addChild(MyBaseSharedPtr child) { return getPtr(); };
};

class MyDerived1 : public MyBase {
        private:
                std::vector<MyBaseSharedPtr> container;
        public:
                MyBaseSharedPtr addChild(MyBaseSharedPtr child) {
                        container.push_back(child);
                        std::cout << "class MyDerived1: adding child\n";
                        return getPtr();
                };

                virtual MyBaseSharedPtr  doSomething() {
                        std::cout << "class MyDerived1: doing something\n";
                        return getPtr();
                }
};

class MyDerived2 : public MyDerived1 {
        public:
                MyBaseSharedPtr doSomething() {
                        std::cout << "class MyDerived2: doing something\n";
                        return getPtr();
                }
};

int main(void ) {
        MyBaseSharedPtr myBase = std::make_shared<MyBase>();
        MyBaseSharedPtr myDerived2 = std::make_shared<MyDerived2>();
        myDerived2->addChild(myBase)->doSomething();
        return 0;
}
0
template<typename _T>
shared_ptr<_T> allocate()
{
    shared_ptr<_T> ptr(new _T);
    // this may need to be changed to 
    // something like (*typename ptr.get()).weak_this
    // if the compiler won't accept a duck-typed _T::weak_this
    ptr.get()->weak_this = weak_ptr<_T>(ptr);
    return ptr;
}

class A
{
    weak_ptr<A> weak_this;
    friend shared_ptr<A> allocate<A>();

    public:
        shared_ptr<A> getPtr(){return weak_this.lock();}
        shared_ptr<A> doSomething()
        {
            // do something
            return getPtr();
        }
};
0

, , , . - :

#include <list>
#include <iostream>

struct Base {
};

template <class Parent>
struct A : Parent {
    std::list<Parent*> children;

    A* addChild(Parent* child) {
        children.push_back(child);
        return this;
    }
};

template <class Parent>
struct B : Parent {
    B* doSomething() {
        std::cout << "Something" << std::endl;
        return this;
    }
};

int main(){
    typedef A< B<Base> > Composed;
    Composed a;
    Composed b;
    a.addChild(&b)->doSomething();
}

, , , , "" (). :

a.doSomething()->addChild(&b); //ERROR! B is not a A

But it will work if you declare:

typedef B< A<Base> > Composed; //Note the order of B and A

I do not know if it suits your needs.

Hope this helps at least give you the opportunity to think about the problem in a different way.

0
source

Source: https://habr.com/ru/post/1619268/


All Articles