新的共享指针&虚函数

时间:2011-11-25 00:43:48

标签: c++ smart-pointers virtual-functions

在我的计划中,我面临另一个困难(我将它们全部存储起来并在burts中提出许多问题:P)。我所拥有的是一个仿函数 - 那些继承自DuplicateFn的仿函数 - 它们都有一个虚拟运算符(),每个孩子都应该写它的版本。

现在其中一个孩子 - 称为合并 - 可能不会成功,在这种情况下它应该尝试回退方法。目前这个类看起来像:

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;
};

我认为问题在这里已经清晰可见 - 在非默认构造函数中,此方法占用了给定参数的所有权。 - 这不是我想要的:它应该复制那个参数并保持对它的所有权 现在我尝试, FallBack(new DuplicateFn(f))但是这也不会起作用 - 因为现在有一个编译错误,它试图用纯虚方法从类中实例化一个对象。

那我该怎么做呢? - 我是否必须为每种类型指定一个特定的构造函数? - 只是为了核心地复制它?或者我必须通过RTTI?我希望有比这更好的方法。

修改 要显示mergeFn如何初始化(和使用):

std::unique_ptr<detail::DuplicateFn> foo;
foo.reset(new detail::MergeFn(this, &Other, DuplicateFns.at(HandleDuplicate)));

DuplicateFns是一个帮助将用户输入(字符串)转换为函数指针的映射。 - 或者就像现在一样,从DuplicateFn指向子类型的对象(指针类型是DuplicateFn *)

然后将其用作回叫方法

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

将2个树组合成一个 - 当SimilarTreeValue返回true时,该条目被视为重复。如果条目是叶子,则调用第3个参数 - 我们正在谈论的仿函数:)。

3 个答案:

答案 0 :(得分:1)

最简单的解决方案(在我看来)是将构造函数的签名更改为需要共享指针:

MergeFn(GMProject const * Out,
        GMProject const * In,
        std::shared_ptr<DuplicateFn> f) /* ... */

第二个选项是使用clone()函数赋予整个类层次结构:

struct Base
{
  virtual Base * clone() const { return new Base(*this); }
};

struct Der1 : Base
{
  virtual Der1 * clone() const { return new Der1(*this); }
};

然后您可以初始化FallBack(f->clone())

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

答案 1 :(得分:0)

  

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

答案 2 :(得分:-1)

您可以使用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; 
};