2010-05-26 62 views
0

我想提高我的程序架構的知識和最近arised給我一個問題,這是related with this pointers issues I posted recently.如何正確設計的使用指針在C++

的事情是類層次,在一個簡單的層次結構中,你A類的指針指向B類,最後指向C類。不要將它與Object Oriented編程的繼承屬性混淆,但基本上我所說的是C類是B類的子類,而B類是A類的孩子。

問題是我希望能夠通過指針直接從Class A訪問Class C(類比的孫子)。其他一些成員指出這是糟糕的設計,主要是因爲如果從類B集合中刪除類C的實例會在類A集合中留下指向「無」的指針。那麼,這是如何正確建模?

非常感謝!

Julen。

+0

我建議你通過「四人幫」來設計圖案書:http://en.wikipedia.org/wiki/Design_Patterns – 2010-05-26 14:28:09

回答

2

而不是使A級意識到每一個C類的,可以考慮使用Composite Pattern

#include <boost/ptr_container/ptr_vector.hpp> 
#include <boost/foreach.hpp> 
#include <iostream> 
#include <stdexcept> 

//------------------------------------------------------------------------------ 
class Component 
{ 
public: 
    typedef boost::ptr_vector<Component> Children; 

    virtual void print() = 0; 
    // Other operations 

    virtual bool isLeaf() {return true;} 

    virtual Children& children() 
     {throw std::logic_error("Leaves can't have children");} 
}; 

//------------------------------------------------------------------------------ 
class Composite : public Component 
{ 
public: 
    void print() 
    { 
     BOOST_FOREACH(Component& child, children_) 
     { 
      child.print(); 
     } 
    } 

    bool isLeaf() {return false;} 

    Children& children() {return children_;} 

private: 
    Children children_; 
}; 

//------------------------------------------------------------------------------ 
class Nut : public Component 
{ 
public: 
    Nut(std::string info) : info_(info) {} 
    void print() {std::cout << info_ << std::endl;} 

private: 
    std::string info_; 
}; 

//------------------------------------------------------------------------------ 
class Bolt : public Component 
{ 
public: 
    Bolt(std::string info) : info_(info) {} 
    void print() {std::cout << info_ << std::endl;} 

private: 
    std::string info_; 
}; 

//------------------------------------------------------------------------------ 
class Wheel : public Composite 
{ 
public: 
    Wheel(std::string info) : info_(info) {} 
    void print() 
    { 
     std::cout << info_ << std::endl; 
     Composite::print(); 
    } 

private: 
    std::string info_; 
}; 

//------------------------------------------------------------------------------ 
class Vehicle : public Composite 
{ 
public: 
    Vehicle(std::string info) : info_(info) {} 
    void print() 
    { 
     std::cout << info_ << std::endl; 
     Composite::print(); 
     std::cout << "\n\n"; 
    } 

private: 
    std::string info_; 
}; 

//------------------------------------------------------------------------------ 
int main() 
{ 
    Wheel* wheel1 = new Wheel("Wheel1"); 
    wheel1->children().push_back(new Nut("Nut11")); 
    wheel1->children().push_back(new Nut("Nut12")); 
    wheel1->children().push_back(new Bolt("Bolt11")); 
    wheel1->children().push_back(new Bolt("Bolt12")); 

    Wheel* wheel2 = new Wheel("Wheel2"); 
    wheel2->children().push_back(new Nut("Nut21")); 
    wheel2->children().push_back(new Nut("Nut22")); 
    wheel2->children().push_back(new Bolt("Bolt21")); 
    wheel2->children().push_back(new Bolt("Bolt22")); 

    Vehicle bike("Bike"); 
    bike.children().push_back(wheel1); 
    bike.children().push_back(wheel2); 

    bike.print(); 
} 

該程序的輸出:

Bike 
Wheel1 
Nut11 
Nut12 
Bolt11 
Bolt12 
Wheel2 
Nut21 
Nut22 
Bolt21 
Bolt22 

注意,當bike.print()被調用時,print被稱爲遞歸地對所有的孩子。沒有父母知道所有孩子的情況下,你就可以對所有孩子進行操作。

Visitor Pattern在複合模式下效果很好,所以我建議你也閱讀一下。特別是如果你有許多操作可以用更基本的操作來實現。

1

我想你所說的是C類派生自B類,派生自A類。不要混淆類層次結構和指向類對象的指針。你可以用單個對象(以及指向對象的單個指針)來完成你正在談論的內容。如果爲類型C的對象創建類型爲C *的指針,則可以訪問在類B和A中定義的所有公共和受保護的方法。或者,如果實現虛擬方法,則可以創建類型爲A *的指針給類型C.在運行時,vtable將用於自動查找該虛擬方法的最低級別實現(即,如果在那裏定義了類別C,否則來自類別B,否則從類別A定義)。有大量用於學習C++基礎知識的優秀資源。如果你搜索的話,我確定有這麼一個列表的話題。

編輯

這裏是一個這樣的環節:https://stackoverflow.com/questions/70159/what-is-the-best-source-to-learn-c

+0

對不起,也許這個例子有誤導性。不,根本沒有繼承權。基本上是A級,我們可以說汽車和B級是車輪,而C級是這些車輪的螺釘部分。問題是我想讓車直接知道所有這些螺絲。 – Julen 2010-05-26 14:26:12

5

不幸的是,你只是重新發明輪子。改變你的方法,所有指針的東西可以實際上自動管理。

如果可能的話,使用組成。讓class A的對象持有class B的對象,該對象將持有class C的對象。這種明顯而簡單的方法可以爲您節省大量時間,使您的應用程序結構更加「更清潔」。

如果你的類可以在相同類型的對象來處理(例如,如果它們共享相同的接口),然後從B派生您CA獲得B。在此之後,您將不得不考慮他們的共享接口 - 根據您的class A中的virtual functions,這就像基類一樣。這實際上是一個棘手的時刻,但是一旦你習慣以這種方式規劃你的接口,你就不會想到以其他方式做它。

另外提一下,如果連這似乎是「當前的問題無法通過動態模擬多態性」或者你「只是想不出一個合適的接口」,再試一次。 而不要試圖發明新的程序架構建設方式,而只是習慣現有的方法。

+0

你所指的是複合模式:http://en.wikipedia.org/wiki/Composite_pattern – 2010-05-26 14:25:51

+0

謝謝科蒂。但是,如果我理解正確,我的類之間沒有任何類型的繼承。只是B是A的一部分,C是B的一部分。同時A必須知道所有C部分。也許事情是我不應該使用指針來模擬這種方法。 – Julen 2010-05-26 14:30:39