C++ 如何在嵌套类中实现多态性?
编辑:底部的具体示例 解释这个问题的最好方法是举例说明(请注意,这个具体例子的解决方案不是我想要的答案) 假设我有一个基类C++ 如何在嵌套类中实现多态性?,c++,inheritance,polymorphism,nested-class,C++,Inheritance,Polymorphism,Nested Class,编辑:底部的具体示例 解释这个问题的最好方法是举例说明(请注意,这个具体例子的解决方案不是我想要的答案) 假设我有一个基类base,它基本上是一个容器: class Base { protected: class BaseNode { protected: BaseNode* next; int id; }; Node* head; public: // ... functionality }; 现在我想推导并改进它,添加一个额外
base
,它基本上是一个容器:
class Base {
protected:
class BaseNode {
protected:
BaseNode* next;
int id;
};
Node* head;
public:
// ... functionality
};
现在我想推导并改进它,添加一个额外的数据字段:
class Derived : public Base {
private:
class DerivedNode: public BaseNode {
char* name;
};
public:
// .. some more functionality
};
我想要的是一个派生的
类,它具有基本
的所有功能,但每个节点也包括一个名称
,而不仅仅是一个id
但如果我查看DerivedNode
的实例,我想要的是:
DerivedNode = {
DerivedNode* next;
int id;
char* name;
};
但我得到的是:
所以DerivedNode()->next->name
将是未定义的
更不用说Base
类只处理BaseNode
s。。。对new
和delete
的所有调用都无法为DerivedNode
中的char*
分配足够的内存
这似乎是一个非常普遍的问题,有什么好办法解决这个问题吗?大多数Base
s功能甚至对DerivedNode
s都非常有用,所以我更愿意保持继承方案的原样
编辑:这可能有用的具体示例
我真的不想放太多的代码,所以我会尝试解释。。。如果有人想看一个例子,我问了一个关于我具体需求的问题
我正在实现一个列表
类。那是我的基础课。它是模板化的(每个节点中的数据都是模板化的,每个节点也有*next和*prev字段),有一个迭代器嵌套类、插入、按迭代器位置删除。。。作品
我想实现一个Forrest
类,它是一个数据节点列表(仍然是模板化的),但是每个节点都包含一个指向该节点的TreeNode
s列表。我之所以要这样做,是因为数据是可排序的,我希望能够在log(n)
time(因此是一个树)中获取它,但它可以以两种不同的方式进行排序(例如,年龄和ID号),所以我需要两个指向相同数据的树
因此:我将Forrest
从List
继承,并派生ForrestNode
以包含指向数据的TreeNode
列表:
class DerivedNode: public List<T>::ListNode {
List<Tree<T*>::TreeNode*> treeNodes;
};
类DerivedNode:公共列表::ListNode{
列出三萜类化合物;
};
基类List
不需要知道新的treeNodes
字段,因为它与列表功能无关-像swap
,get\u head
,is\u empty
这样的方法应该工作相同,创建新节点的工作应该基本相同(需要分配更多内存,但新的treeNodes
字段不应使用数据初始化)
但是,新的
Forrest
类将覆盖基本的List
s方法,但仅使用添加的功能—例如,在插入后(常规列表插入),指针将插入到相关树中,然后新树节点的地址将添加到树节点列表中。如@stefaanv所述,我们可以使用模板实现您想要的。请验证以下程序:
#include <iostream>
using namespace std;
class Base {
protected:
template<typename Z>
class BaseNode{
protected:
Z* next;
int id;
};
public:
};
class DerivedNode;
class Derived : public Base{
private:
class DerivedNode: public BaseNode<DerivedNode>{
public:
const char* name;
void setId(int val){id = val;}
void setNext(DerivedNode* nx){next = nx;}
DerivedNode* getNext(){return next;}
};
DerivedNode* derHead;
public:
Derived()
{
DerivedNode* node1 = new DerivedNode();
node1->name = "Nik";
node1->setId(1);
node1->setNext(NULL);
DerivedNode* node2 = new DerivedNode();
node2->name = "Aka";
node2->setId(2);
node2->setNext(NULL);
node1->setNext(node2);
derHead = node1;
}
DerivedNode* getHead(){return derHead;}
void print()
{
DerivedNode* tmp = derHead;
while(tmp != NULL)
{
cout<<tmp->name<<endl;
tmp = tmp->getNext();
}
}
};
int main()
{
Derived obj;
obj.print();
return 0;
}
#包括
使用名称空间std;
阶级基础{
受保护的:
模板
类BaseNode{
受保护的:
Z*下一步;
int-id;
};
公众:
};
类派生节点;
派生类:公共基{
私人:
类DerivedNode:公共BaseNode{
公众:
常量字符*名称;
void setId(int val){id=val;}
void setNext(DerivedNode*nx){next=nx;}
DerivedNode*getNext(){return next;}
};
DerivedNode*derHead;
公众:
派生的()
{
DerivedNode*node1=新的DerivedNode();
node1->name=“Nik”;
node1->setId(1);
node1->setNext(空);
DerivedNode*node2=新的DerivedNode();
node2->name=“Aka”;
node2->setId(2);
node2->setNext(空);
node1->setNext(node2);
derHead=节点1;
}
DerivedNode*getHead(){return derHead;}
作废打印()
{
DerivedNode*tmp=derHead;
while(tmp!=NULL)
{
cout您只需将Base::BaseNode转换为模板,并提供next
成员变量的类型作为类型参数,如下所示:
class Base {
protected:
template <class Derived>
class BaseNode {
protected:
Derived* next;
int id;
};
Node* head;
public:
// ... functionality
};
class Derived : public Base {
private:
class DerivedNode: public BaseNode<DerivedNode> {
char* name;
};
public:
// .. some more functionality
};
类基{
受保护的:
模板
类BaseNode{
受保护的:
导出*下一步;
int-id;
};
节点*头;
公众:
//…功能
};
派生类:公共基{
私人:
类DerivedNode:公共BaseNode{
字符*名称;
};
公众:
//…更多功能
};
如果您确实需要多态性,这将非常困难,但因为您似乎没有使用多态性(DerivedNode()->next->name
),您可能想看看如何用模板解决这个问题。您能分享一些这样的设计会有帮助的特定场景吗?这将如何解决分配问题?假设我在Base
中有一个insert
方法。它应该调用new BaseNode()
…我必须重写Derived
中的insert
方法来调用new-DerivedNode()
你能举个例子说明这个insert方法实际会做什么吗?它会将什么数据插入到你的数据结构中?你如何在不覆盖派生的insert方法的情况下将名称输入到节点中?insert方法会创建一个新节点并将其插入基类的开头(如列表),而name
的默认构造函数对我来说已经足够好了,我将在Derived
中编写方法来设置/获取名称。如果不将Base转换为模板,我看不到一个很好的解决方案。如果你想让Base能够通用地处理节点,我认为没有办法解决这个问题。我问@Kristian dazze这个问题评论中的问题:这将如何
class Base {
protected:
template <class Derived>
class BaseNode {
protected:
Derived* next;
int id;
};
Node* head;
public:
// ... functionality
};
class Derived : public Base {
private:
class DerivedNode: public BaseNode<DerivedNode> {
char* name;
};
public:
// .. some more functionality
};