2014-11-21 88 views
0

編輯:在解釋這個問題底部如何在嵌套類中實現多態?

最好的方法具體的例子是例如(請注意,這個具體的例子的解決方案是不是我要找的答案)。

說我有一個基類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 
}; 

我想要的是一個Derived類,其所有功能爲Base,但每個節點也包含一個name,而不僅僅是一個id

但如果我看的DerivedNode一個實例,我想要什麼是:

DerivedNode = { 
    DerivedNode* next; 
    int id; 
    char* name; 
}; 

但我是:

DerivedNode = { 
    BaseNode* next; 
    int id; 
    char* name; 
}; 

所以DerivedNode()->next->name將是不確定的!

更不用說了Base類只處理BaseNode小號......到newdelete所有呼叫在DerivedNode不會分配爲char*足夠的內存。

這似乎是一個非常普遍的問題,有沒有解決這個問題的一些簡潔方法?大多數Base小號功能,甚至會爲DerivedNode真的非常有用,所以我寧願保持繼承方案,因爲它是...

編輯:對時,這可能是有用的一個具體的例子

我真的不想放很多代碼,所以我會盡力解釋......如果有人想看一個例子,我已經問了一個關於我的具體需求的問題here

我正在實施List類。那是我的基礎班。它是模板化的(每個節點中的數據都是模板化的,每個節點也有* next和* prev字段),具有迭代器嵌套類,插入,刪除迭代器位置......的作品。

我想實現一個Forrest類,它是一個數據節點列表(仍是模板化的),但每個節點都包含一個指向節點的列表TreeNode。我想這樣做,因爲數據是可排序的,我希望能夠在log(n)時間(因此,一棵樹)中獲取它,但它可以通過兩種不同的方式(例如年齡和ID號)排序,所以我需要兩個指向相同數據的樹。

所以:我做了Forrest繼承List,並衍生ForrestNode以包括TreeNode s表示指向數據的列表:

class DerivedNode: public List<T>::ListNode { 
    List<Tree<T*>::TreeNode*> treeNodes; 
}; 

基類List並不需要了解新的treeNodes字段,因爲它與列表功能無關 - 像swap,get_head,get_head,is_empty這樣的方法應該工作相同,並且創建新節點應該幾乎相同(需要分配更多內存,但新的treeNodes字段不應該初始化與數據)。

Forrest類,但是,將覆蓋基底List小號的方法,但僅與加入功能 - 例如,插入(常規列表插入)之後,指針將被插入到相應的樹,然後新樹節點的地址將被添加到treeNodes列表中。

+0

這將是如果你確實需要多態性,這很困難,但是由於你似乎沒有使用多態('DerivedNode() - > next-> name'),所以你可能想看看如何用模板來解決這個問題。 – stefaanv 2014-11-21 10:03:06

+0

可以請你分享一些特定的場景,這樣的設計會有幫助嗎? – Nik 2014-11-21 11:33:34

+0

增加了一個例子 – Dori 2014-11-21 11:57:09

回答

0

你可以簡單地把你的基地:: 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 
}; 
+0

這將如何解決分配問題?假設我在'Base'中有一個'insert'方法。它應該調用'new BaseNode()'...我將不得不重寫'Derived'中的'insert'方法來調用'new DerivedNode()' – Dori 2014-11-21 11:22:03

+1

你能舉一個這個插入方法實際上會做什麼的例子嗎?它將什麼數據插入到數據結構中?而且,如何在不覆蓋Derived中的insert方法的情況下將名稱放入節點? – 2014-11-21 11:27:59

+0

插入方法會創建一個新節點並將其插入Base類的頭部(如列表),並且'name'的默認構造函數對我來說足夠好,我會在'Derived'中編寫方法來設置/得到名字 – Dori 2014-11-21 11:40:29

0

正如@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; 
} 
+0

我在評論中問@Kristian Duske這個問題:這將如何解決分配問題?具體來說,這個例子沒有利用'Base'類的功能,你需要在'Derived'中編寫很多全新的方法,不是嗎? – Dori 2014-11-21 11:24:38

+0

你是什麼意思「不利用基類的功能」。你知道你永遠不能從外面修改受保護的成員。你只能通過子類來做到這一點,在這裏我只是描述了更新它們的方法。代替多個功能,您可以擁有一個更新功能。 – Nik 2014-11-21 11:32:28