继承自enable_shared_from_this返回self的shared_ptr的类的子类

时间:2015-12-09 21:53:01

标签: c++

我想知道是否还有像这个伪代码那样的事情:

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()
}

我的目标是一个对象代表一个视图(如在MVC中的V中),以及能够为链式调用返回自身的方法。例如:->setTop(0)->addChild(child1)->setBottom(0)

我已经读过,做一些超载<<运算符的事情可能更容易接受,但我看不到工作得很好或看起来很漂亮。

我有一个想法是制作一个名为VIEW(name,parent)的宏,它会使用模板扩展,但我遇到了自我引用的默认模板参数问题。

非常感谢任何帮助。

- 编辑 -

在坚果壳中,我希望有一个继承自enable_shared_from_this的基类。基类将有一个方法,如doSomething,返回共享指针。当派生类继承自基类时,我希望doSomething方法返回一个指向派生类的共享指针。我希望能够在不覆盖派生类中的doSomething的情况下执行此操作。

4 个答案:

答案 0 :(得分:1)

这种概念将被存在于类定义之外的扩展方法所涵盖,不会违反类权限,但可以像C#中存在的方法一样被调用,但目前不存在于C ++中。 C#中的代码如下所示:

// 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());
    }
}

至于将模板唯一地应用于每个派生类型的简单内部方式,我不确定。这样做的原因是你想要的功能不是方法继承,而是每个未来的类都继承了一个自动专门化的模板(并且结果方法不会被继承或隐藏。)为此目的,C ++类需要有非继承的专用公共方法,当前访问权限不包括公共,私有和受保护或模板功能。

我很高兴能找到一种很好的方法来解决操作员链接问题。

因为我已经离开并浪费你的时间,我试图这样做:

#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 :(得分:0)

以下是您可能尝试完成的示例(尽管我不确定我是否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;
}

答案 2 :(得分:0)

var

答案 3 :(得分: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

但如果您声明:

,这将有效
typedef B< A<Base> > Composed; //Note the order of B and A

我不知道它是否符合您的需求。

希望这至少有助于您以不同的方式思考问题。