2015-05-28 56 views
1

我有一個具有相當複雜的繼承結構的程序,所以我不會用它來顯示我的問題,而是使用不好的樣式以下結構讓事情變得簡單:C++將派生類存儲在單個向量中,派生類不包含重定義方法

class A { 
public: 
    int va1; 
    int va2; 
    string va3; 

    virtual void fa1(int x1, string x2) { 
     // method body 
    } 

    int fa2 (bool y1, double y2) { 
     // method body 
    } 

    A() { 

    } 

    virtual ~A() { 

    } 
}; 

class B : 
    public A 
{ 
public: 
    bool ab1; 
    double ab2; 
    long double ab3; 

    bool fb1(double x1) { 
     //method body 
    } 

    long double fb2() { 
     //method body 
    } 

    B(int z1) { 
     ab2 = z1; 
    } 

    virtual ~B() { 

    } 
}; 

class C : 
    public A 
{ 
public: 
    int ac1; 

    long double fc1() { 
       //method body 
    } 

    virtual void fa1(int x1, string x2) { 
     // method body 
    } 

    C() { 

    } 

    virtual ~C() { 

    } 
}; 

正如你所看到的,B和C主要由完全新的變量和方法,並使用A-指針結合虛擬的方法獲得了不重新定義從A 那些結果,」工作。

到現在爲止,我總是使用單獨的向量或數組作爲派生類,因爲我很少編寫主要由僅重新定義基類的方法的派生類組成的程序。

我知道我不能簡單地創建一個As的向量並且放入Bs和Cs而不會丟失信息。

我的問題是,是否有可能將As,Bs和Cs以指針或其他形式存儲在單個向量中,並且仍然可以訪問A中不存在的所有方法和變量?

如果它不適用於矢量,是否有替代品(數組可能)?

該代碼可以包含現代C++(標準,std :: string而不是char *等),因爲不需要與C或傳統C++兼容。

+1

您可以隨時將所有內容存儲爲'A *',然後嘗試['dynamic_cast'](http://en.cppreference.com/w/cpp/language/dynamic_cast)到所需的派生類型。如果演員失敗失敗,那麼你知道你不能調用該函數。 – NathanOliver

+1

爲什麼_使用與虛擬方法結合的指針將無法工作_?此外,你會失去什麼信息,只需創建一個As的向量並放入Bs和Cs_中? – Amit

+0

[OT]由於何時使用'std :: string'變成「* modern C++ *」?! – yzt

回答

1

這可以通過使用指針或更好的載體,的shared_ptr這樣的載體來完成:

vector<shared_ptr<A>> v;  // vector of shared ponters to A 
v.push_back(make_shared<A>()); 
v.push_back(make_shared<B>(2)); 
v.push_back(make_shared<C>()); 

shared_ptr<A> pa = v[1];  // this one is a B but in real life we would'nt know 
           // I can use all the A methods without question 
shared_ptr<B> pb = dynamic_pointer_cast<B>(pa); // attempt to cast it to a B 
if (pb) {      // if casting succeded 
    pb->fb2();      // I call the B method 
} else cout << "Not a B"<<endl; // if not, I know that it's an A but not a B 

的原則是,你在矢量(共享)指針A.所以,你存儲總是可以訪問其A::成員。

作爲基類是多態的(即,它具有至少一個虛函數),則dynamic_cast(在shared_ptr的情況下dynamic_pointer_cast)可被用來嘗試的指針轉換爲一個派生類的指針(例如B)。如果投射成功(非空指針),那麼您知道您可以訪問B::成員。

shared_ptr與raw指針的使用有助於內存管理:如果一個對象不再使用,它​​會自動刪除。

這裏是一個online demo

+0

謝謝,我會試試看。 – Willi

+0

你會說使用這樣的載體是一個好主意,還是在大多數情況下,比實際的價值更麻煩?例如,在我的程序中,將不同的派生類存儲在它們自己的向量中是絕對有可能的,只要添加一些開關,if語句等等。 – Willi

+0

@Willi我已經添加了一個到在線演示的鏈接。不知道你的程序是做什麼的,很難給出客觀的答案,但是通常使用這種向量是一個非常好的主意。稍後您可以輕鬆添加新的派生類。也許你也看看訪客設計模式。 – Christophe