在我的计划中,我面临另一个困难(我将它们全部存储起来并在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个参数 - 我们正在谈论的仿函数:)。
答案 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;
};