从内部类继承

Inheritance from inner class

本文关键字:继承 内部类      更新时间:2023-10-16

我在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正在使用直接实例化nodetree的基本构造函数,因此derivedTreetree都将有一个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对象而不是derivedNodetree对象。

我会为此使用模板,类似于这些内容:

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也有一个很好的解决方案。我真的不能给你一个选择一种或另一种解决方案的理由。