使用回调函数从构造函数调用虚拟/派生方法的替代方法?
Alternative to calling virtual/derived methods from constructor using callback function?
我遇到上述问题的情况。我想构建一个带有关联节点的树。由于所有树的行为都相同,但类型不同,本着继承的精神,我希望能够使用基类定义的相同树构造例程来构造不同类型的树。我想知道针对我的情况的最佳实践是什么。
struct Tree
{
struct Node { std::list<std::shared_ptr<Node>> children_; };
Tree()
{
root_ = CreateNode();
// carry on adding nodes to their parents...
}
virtual std::shared_ptr<Node> CreateNode() { return std::shared_ptr<Node>(new Node()); }
std::shared_ptr<Node> root_;
};
struct TreeDerived : public Tree
{
struct NodeDerived : public Tree::Node {};
TreeDerived() : Tree() {}
virtual std::shared_ptr<Node> CreateNode() { return std::shared_ptr<NodeDerived>(new NodeDerived()); }
};
问题是在构造基(显然(之前我无法调用派生函数,并且它使用CreateNode
方法的基本实现,该方法始终使用基节点实现构造树。这意味着我可以在不延迟树木数量的情况下构建树木。显而易见的解决方案是模板树以采用不同的节点类型,使用特征强制执行节点类型?但是,这也意味着所有方法的定义都必须在标头中?这门课很肉,所以如果可能的话,我想避免这种情况,所以我考虑传递一个为我做这件事的 lambda。
struct Tree
{
struct Node { std::list<std::shared_ptr<Node>> children_; };
Tree(std::function<std::shared_ptr<Node>()> customNodeConstructor)
{
root_ = customNodeConstructor();
// carry on adding nodes to their parents... using the customNodeConstructor to create the nodes.
}
std::shared_ptr<Node> root_;
};
struct TreeDerived : public Tree
{
struct NodeDerived : public Tree::Node {};
TreeDerived(std::function<std::shared_ptr<Node>()> customNodeConstructor) : Tree(customNodeConstructor) {}
};
这允许我派生和传递与派生树相关的customNodeConstructor
。类型安全是部分强制执行的,因为返回的shared_ptr
对象必须派生自Tree::Node
,尽管没有强制派生到派生节点类型。
即一个TreeDerived
实例化,也许应该使用TreeDerived::NodeDerived
只强制使用Tree::Node
或派生类型,但不一定TreeDerived::NodeDerived
。
然后可以这样使用...
Tree tree([]() { return std::shared_ptr<Tree::Node>(); });
TreeDerived treeDerived([]() { return std::shared_ptr<TreeDerived::NodeDerived>(); });
这是好的做法,还是我应该在不模板化 Tree 对象的情况下做更多/其他事情?
非常感谢。
这个想法是合理的;但是,在派生类中创建"自定义树构造函数"比在外部使用它更安全。这样,您就不会获得不正确的节点类型。在代码形式中:
struct TreeDerived : public Tree
{
struct NodeDerived : public Tree::Node {};
TreeDerived() : Tree([]() { return std::make_shared<NodeDerived>(); }) {}
};
另请注意,在一般情况下,std::function
每次调用都会产生不平凡的运行时开销。如果您总是要传入无状态 lambda,请考虑在Tree
构造函数中采用纯函数指针:
Tree(std::shared_ptr<Node> (*customNodeConstructor)())
{
root_ = customNodeConstructor();
// carry on adding nodes to their parents... using the customNodeConstructor to create the nodes.
}
作为这种"传入自定义创建者"方法的替代方法,还可以仅将Tree
的构造函数转换为函数模板。然后它可能看起来像这样:
template <class T> struct TypeTag;
struct Tree
{
struct Node { std::list<std::shared_ptr<Node>> children_; };
template <class ConcreteNode>
Tree(TypeTag<ConcreteNode>)
{
root_ = std::make_shared<ConcreteNode>();
// carry on adding nodes to their parents...
}
std::shared_ptr<Node> root_;
};
struct TreeDerived : public Tree
{
struct NodeDerived : public Tree::Node {};
TreeDerived() : Tree(TypeTag<NodeDerived>{}) {}
};
然后,必须在某个位置定义构造函数模板,其中派生自Tree
的所有类都可以看到其定义(因此很可能在头文件中(,但Tree
类的其余部分保持正常。
我很难理解为什么你需要你做的设计(至少可以说,从基类内部的结构派生结构内部的派生结构看起来有问题(。
话虽如此,您可以考虑mclow的常见问题解答中的解决方法。
tl;DR 是将逻辑从构造函数移动到 init(( 中,并在 init(( 中调用虚拟函数"work"。
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 为什么此派生对象无法访问基类的后递减方法?
- 是否可以为 QPixmap 派生类嵌入缩放方法?
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 使用基类中的派生方法运行线程,而无需使用模板
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- 在派生类中使用基类的私有成员变量的最佳方法
- 如何在从抽象基派生的类中实现相同的方法?
- 调用从模板派生的类的静态方法,而不指定模板
- 如何在工厂方法中返回指向基于基础操作系统的派生类的有效指针
- 如何将成员函数作为参数传递并在派生对象上执行方法列表
- 从基类实例调用派生类方法而不进行强制转换
- 派生类调用父类的方法,该方法调用重写的虚拟方法调用错误的方法
- 从纯虚拟类 (A) 派生的指针无法访问来自纯类 (B) 的重载方法
- 通过基类接受方法转发派生 UniquePtr 的右值会移动引用而不是复制
- C ++基础私有方法在将自身转换为派生类后可以访问吗?
- C++ 使用派生类方法更改基类数据成员
- 如何使用派生类特定的方法:派生类中的派生成员
- 使用抽象类的指针访问派生类的方法;派生类似乎也是抽象的