C++ 新的共享指针&;虚拟函数

C++ 新的共享指针&;虚拟函数,c++,smart-pointers,virtual-functions,C++,Smart Pointers,Virtual Functions,在我的程序中,我面临着另一个困难(我将它们全部存储起来,并以burts:p的形式询问许多问题)。我所拥有的是一个函子——这些函子都是从DuplicateFn继承而来的——它有一个虚拟操作符(),每个子函数都需要编写它的版本 现在,一个名为merge的child可能不会成功,在这种情况下,它应该尝试一种回退方法。目前,该类看起来如下所示: class MergeFn : public DuplicateFn { public: MergeFn() : FallBack(new SkipFn

在我的程序中,我面临着另一个困难(我将它们全部存储起来,并以burts:p的形式询问许多问题)。我所拥有的是一个函子——这些函子都是从
DuplicateFn
继承而来的——它有一个虚拟操作符(),每个子函数都需要编写它的版本

现在,一个名为merge的child可能不会成功,在这种情况下,它应该尝试一种回退方法。目前,该类看起来如下所示:

class MergeFn : public DuplicateFn {
public:
    MergeFn() : FallBack(new SkipFn())
    {
    }
    MergeFn(GMProject const* Out, GMProject const* In, DuplicateFn* f) 
        : DuplicateFn(Out, In), FallBack(f)
    {
    }
    virtual void operator() (GMProject::pTree& tOut, const GMProject::pTree& tIn) const {
        if (!GMProject::isMergeable(tOut.GetName())) {
            (*FallBack)(tOut, tIn); //virtual table resolves this to the correct class
        } else {
        }
    }
private:
    std::shared_ptr<DuplicateFn> FallBack;
};
DuplicateFns是帮助将用户输入(字符串)转换为函数指针的映射。-或者像现在一样,从DuplicateFn(指针类型为DuplicateFn*)指向子类型的对象的指针

然后将其用作回调方法

ProjectTree.combine_if(tree, &SimilarTreeValue, foo.get());

它将两棵树合并为一棵树-当SimilarTreeValue返回true时,该条目被视为重复条目。如果条目是叶,则调用第三个参数-我们正在讨论的函子:)。

您可以使用shared_ptr的构造函数,该构造函数接受自定义析构函数并为其传递空函数。比如说

void dontDelete(DuplicateFn *pFn ) {
  // Do nothing!
  }

class MergeFn : public DuplicateFn { 
public: 
    MergeFn() : FallBack(new SkipFn()) 
    { 
    }

    MergeFn(GMProject const* Out, GMProject const* In, DuplicateFn* f)  
        : DuplicateFn(Out, In), FallBack(f, dontDelete) 
    { 
    }

    virtual void operator() (GMProject::pTree& tOut, const GMProject::pTree& tIn) const { 
        if (!GMProject::isMergeable(tOut.GetName())) { 
            (*FallBack)(tOut, tIn); //virtual table resolves this to the correct class 
        } else { 
        } 
    }

private: 
    std::shared_ptr<DuplicateFn> FallBack; 
}; 
void dontDelete(重复fn*pFn){
//什么都不要做!
}
类MergeFn:public DuplicateFn{
公众:
MergeFn():回退(新SkipFn())
{ 
}
合并Fn(GMProject const*Out、GMProject const*In、DuplicateFn*f)
:重复FN(输出,输入),回退(f,不删除)
{ 
}
虚拟void操作符()(GMProject::pTree&tOut,const GMProject::pTree&tIn)const{
如果(!GMProject::ismergable(tOut.GetName()){
(*FallBack)(tOut,tIn);//虚拟表将其解析为正确的类
}否则{
} 
}
私人:
std::共享的ptr回退;
}; 
在我看来,最简单的解决方案是更改构造函数的签名,使其已经需要共享指针:

MergeFn(GMProject const * Out,
        GMProject const * In,
        std::shared_ptr<DuplicateFn> f) /* ... */
然后可以初始化
回退(f->clone())

就我个人而言,我会选择第一个版本,我还会检查用唯一指针替换共享指针是否可行

新副本fn(f)

这将只对函子
f
进行切片

您需要克隆功能:

#include <typeinfo>
#include <cassert>

template <class T>
// runtime checked clone function
// T::do_clone() must be accessible to checked_clone
T *checked_clone (const T* that) {
    T *p = that->do_clone();
    assert (typeid (*p) == typeid (*that));
    return p;
}

// clone for an abstract class
#define IMPLEMENT_CLONE_ABSTRACT(Class) \
    friend Class *checked_clone<Class> (const Class* that); \
 \
public: \
    Class *clone_naked() const { \
        return checked_clone (this); \
    } \
    unique_ptr<Class> clone_unique() const { \
        return unique_ptr<Class> (checked_clone (this)); \
    } \     \
private: \
    virtual Class *do_clone() const = 0; \
/* end of IMPLEMENT_CLONE_ABSTRACT */

class Base {
    IMPLEMENT_CLONE_ABSTRACT(Base)
};

// clone for a concrete class
#define IMPLEMENT_CLONE_CONCRETE(Class) \
    friend Class *checked_clone<Class> (const Class* that); \
 \
public: \
    Class *clone_naked() const { \
        return checked_clone (this); \
    } \
    unique_ptr<Class> clone_unique() const { \
        return unique_ptr<Class> (checked_clone (this)); \
    } \     \
 \
private: \
    virtual Class *do_clone() const {  \
        return new Class (*this); \
    } \
/* end of IMPLEMENT_CLONE_CONCRETE */

class Derived : public Base {
    IMPLEMENT_CLONE_CONCRETE(Derived)
};
#包括
#包括
样板
//运行时检查克隆函数
//T::do_clone()必须可供选中的_clone访问
T*已检查\u克隆(常数T*that){
T*p=that->do_clone();
断言(typeid(*p)=typeid(*that));
返回p;
}
//抽象类的克隆
#定义实现\克隆\抽象(类)\
好友类*已选中\u克隆(const类*该类)\
\
公众:\
类*clone_裸()常量{\
返回选中的\u克隆(此)\
} \
唯一的克隆唯一的()常量{\
返回唯一的\u ptr(选中的\u克隆(此))\
} \     \
私人:\
虚拟类*do_clone()常量=0\
/*实施结束\u克隆\u摘要*/
阶级基础{
实现克隆抽象(基本)
};
//具体类的克隆
#定义工具克隆混凝土(类)\
好友类*已选中\u克隆(const类*该类)\
\
公众:\
类*clone_裸()常量{\
返回选中的\u克隆(此)\
} \
唯一的克隆唯一的()常量{\
返回唯一的\u ptr(选中的\u克隆(此))\
} \     \
\
私人:\
虚拟类*do_clone()常量{\
返回新类(*this)\
} \
/*机具结束\u克隆\u混凝土*/
派生类:公共基{
实施克隆混凝土(派生)
};

“您可以使用shared_ptr的构造函数,它接受一个自定义析构函数并为其传递一个空函数。”每当我读到这篇文章时,我都认为“试图用一个便宜的技巧摆脱设计问题是不行的”。这是另一个例子。@curiousguy:
unique\u ptr
的重量要轻得多(没有动态分配,没有虚拟调度)。如果您确实需要共享所有权,请仅使用
shared\u ptr
。“如果您确实需要共享所有权,请仅使用shared\u ptr。”我在这里看到至少两个所有者:呼叫者和被呼叫者。
unique\u ptr
类型的函数参数意味着所有权的转移。如果来电者仍然想要所有权怎么办?哪个来电者?我们不知道。我只能看到构造函数参数。完全可能只需要一个所有者。无论如何,只有OP可以决定,因为我们对上下文一无所知。@KerrekSB嗯,但我真的需要“转移”所有权——或者至少我需要确保外部世界不能触碰指针。但是同时,外部世界也不应该被这个类改变。@paul23:我相信,你可以用一个唯一的指针来完成所有这些。没有上下文是不可能说出来的——你能给出一个小的,有代表性的例子,说明你打算如何使用这个类吗?
struct Base
{
  virtual Base * clone() const { return new Base(*this); }
};

struct Der1 : Base
{
  virtual Der1 * clone() const { return new Der1(*this); }
};
#include <typeinfo>
#include <cassert>

template <class T>
// runtime checked clone function
// T::do_clone() must be accessible to checked_clone
T *checked_clone (const T* that) {
    T *p = that->do_clone();
    assert (typeid (*p) == typeid (*that));
    return p;
}

// clone for an abstract class
#define IMPLEMENT_CLONE_ABSTRACT(Class) \
    friend Class *checked_clone<Class> (const Class* that); \
 \
public: \
    Class *clone_naked() const { \
        return checked_clone (this); \
    } \
    unique_ptr<Class> clone_unique() const { \
        return unique_ptr<Class> (checked_clone (this)); \
    } \     \
private: \
    virtual Class *do_clone() const = 0; \
/* end of IMPLEMENT_CLONE_ABSTRACT */

class Base {
    IMPLEMENT_CLONE_ABSTRACT(Base)
};

// clone for a concrete class
#define IMPLEMENT_CLONE_CONCRETE(Class) \
    friend Class *checked_clone<Class> (const Class* that); \
 \
public: \
    Class *clone_naked() const { \
        return checked_clone (this); \
    } \
    unique_ptr<Class> clone_unique() const { \
        return unique_ptr<Class> (checked_clone (this)); \
    } \     \
 \
private: \
    virtual Class *do_clone() const {  \
        return new Class (*this); \
    } \
/* end of IMPLEMENT_CLONE_CONCRETE */

class Derived : public Base {
    IMPLEMENT_CLONE_CONCRETE(Derived)
};