我在C++中实现了一个二叉搜索树,现在我正在尝试从中继承。
基础树:
#ifndef TREE_HPP
#define TREE_HPP
class tree {
public:
class node {
public:
virtual int foo() { return 1; }
node() = default;
virtual ~node() = default;
};
node* root;
tree() : root(new node) {}
virtual ~tree() { delete root; }
};
#endif
派生树:
#ifndef DERIVED_TREE_HPP
#define DERIVED_TREE_HPP
#include "tree.hpp"
class derivedTree : public tree {
public:
class derivedNode : public node {
public:
virtual int foo() { return 2; }
};
};
#endif
主要:
#include "derivedTree.hpp"
#include "tree.hpp"
#include <iostream>
using std::cout;
int main() {
tree t1;
derivedTree t2;
cout << "Hey! " << t1.root->foo() << "n";
cout << "Hey! " << t2.root->foo() << "n";
}
输出为:
Hey! 1
Hey! 1
我希望它是 1 和 2。 我认为这是因为root
是指向基础树的指针,因此调用tree::foo()
.如何从树继承,使其包含派生节点?
欢迎来到 StackOverflow!
虚拟方法的作用是使您能够根据实例化的实际类而不是指针的类型来调用方法。
因此,在您的情况下,root->foo()
会根据实际类调用该方法,而不是总是调用node
实现。
但是,要调用derivedNode
实现,您必须实例化它!就像现在一样,您的derivedTree
正在使用直接实例化node
的tree
的基本构造函数,因此derivedTree
和tree
都将有一个node
对象作为root
!
为了解决这个问题,如其他答案所示,您可以向tree
添加一个接受外部node
指针的构造函数,并在derivedTree
的构造函数中使用该构造函数,以使用指向derivedTree
的指针初始化root
。
像这样:(可运行的链接(
class tree {
public:
class node {
public:
virtual int foo() { return 1; }
node() = default;
virtual ~node() = default;
};
node* root;
tree(): root(new node) {};
tree(node* d) : root(d) {}; // here we initialize the root pointer with a given pointer
virtual ~tree() { delete root; };
};
class derivedTree : public tree {
public:
class derivedNode : public node {
public:
virtual int foo() { return 2; }
};
derivedTree(): tree(new derivedNode) {}; // here we use the added constructor to create a derivedNode and set it as root
};
using std::cout;
int main() {
tree t1;
derivedTree t2;
cout << "Hey! " << t1.root->foo() << "n";
cout << "Hey! " << t2.root->foo() << "n";
}
请注意,无法直接在派生构造函数中初始化root
,因为该语言允许在初始值设定项列表中仅放置实际类的字段而不是派生字段,并且根据编译器的不同,您将有创建内存泄漏的风险。
您可以添加另一个构造函数,该构造函数采用node*
类型的指针用于tree
,并使用该参数初始化root
。然后,您可以传递相应的指针。例如
class tree {
public:
...
tree(node* r) : root(r) {}
};
class derivedTree : public tree {
public:
...
derivedTree() : tree(new derivedNode) {}
};
住
您遇到的问题不在于继承,而在于嵌入node
对象而不是derivedNode
的tree
对象。
我会为此使用模板,类似于这些内容:
template <typename NodeType>
class treeT {
public:
NodeType* root;
tree() : root(new NodeType) {}
virtual ~tree() { delete root; }
};
class node {
public:
virtual int foo() { return 1; }
node() = default;
virtual ~node() = default;
};
class derivedNode : public node {
public:
virtual int foo() { return 2; }
};
using tree = treeT<node>;
using derivedTree = treeT<derivedNode>;
如果你真的想要内部类,你可以使用一种CRTP,但我想这将是过度工程化。
请注意,@songyuanyao也有一个很好的解决方案。我真的不能给你一个选择一种或另一种解决方案的理由。