2015-02-06 231 views
0

本質上,我試圖解決無法將派生類型作爲派生類型存儲在基類型的(值)數組中的問題。我有多個存儲一到三個整數的類,但必須有非常不同的函數集。我會使用一個指針數組,但是整個數組是向前遍歷的,然後不斷地向後遍歷,主要是線性的,所以把它們全部放在內存中是比較好的。我可以創建多個數組,每個類型都有一個數組,然後是指向每個數組的指針數組,但是這樣做會非常笨拙,實際上不會像每個元素在前一個元素和後一個元素之間整齊排列一樣它按運行時訪問的順序排列。指向類類型的指針

所以我在想的是,我用三個整數和一個指針做一個POD結構,然後用這些指針填充一個數組,然後使用該指針訪問多態函數。它最終會沿着這些路線的東西:(此處原諒糟糕的編碼,我只是想傳達的概念)

class A { 
    int aa(&foo f) { return 1; } 
    int dd() { return 9; } 
}; 
class B : A { 
    int aa(&foo f) { return f.b; } 
}; 
class C : A { 
    int aa(&foo f) { return cc() + f.c - f.a; } 
    int cc() { return 4; } 
}; 
class D : B { 
    int dd() { return 7; } 
}; 
struct foo{ int a, b, c; A* ptr; }; 

const A AA = A(); const B BB = B(); const C CC = C(); const D DD = D(); 
foo[100] foos; 

init() { 
    foo[0] = foo{ 1, 2, 3, &BB }; 
    // etc fill foos with various foo elements 
} 
bar(){ 
    for (int i = 0; i < 100; ++i){ 
     print foos[i].ptr.aa(&foos[i]); 
     print foos[i].ptr.dd(); 
    } 
} 
main(){ 
    init(); 
    while(true) 
     bar(); 
} 

我只是想知道這是否是去了解我想要的東西的最佳方式實現還是有更好的解決方案?理想情況下,我只是指向一個類而不是一個類的實例,但我不認爲我真的可以這樣做...... 理想情況下我會將它們作爲多個派生類型存儲在數組中,但出於顯而易見的原因不會飛。

+0

是否有一個原因,你不能只使用歧視聯盟,如Boost.Variant? – Useless 2015-02-06 10:35:38

+0

除了從來沒有遇到過他們?我不確定。我如何在保持相同類型的同時在每個函數中沒有一堆笨拙的開關語句的情況下製作一個多態的? – User6897 2015-02-06 13:12:17

+0

好吧,只是檢查你是否知道他們,並排除他們。他們應該做你所需要的事情,用訪問而不是轉換語句。 – Useless 2015-02-06 16:53:08

回答

0

你在找什麼是虛擬功能。

在波紋管例如:

class A 
    { 

     virtual void foo(){printf("A is called");}; 
    } 
    class B : public A 
    { 
     void foo(){printf("B is called");}; 
    } 

    ... 
    A* ptr = new B(); 
    ptr->foo(); 

會產生 「B被稱爲」。

如果您不想使用虛擬功能(例如爲了節省內存),您可以使用動態轉換,但這會導致顯着的性能損失。

請注意,您不需要至少有1個虛擬功能來執行動態投射。

在波紋管的例子:

class A {...} 
    class B : public A {...} 
    class C : public A {...} 

    A* ptr1 = new C(); 
    B* ptr2 = dynamic_cast<B*>(ptr1); 
    C* ptr3 = dynamic_cast<C*>(ptr1); 

PTR2將爲空,並且將PTR3有一個值。通過擁有自己的打字機制

 if (ptr2) 
    { 
     ptr2->bb(); 
    } else if (ptr3) 
    { 
     ptr3->cc(); 
    } 

最後,你就可以擺脫動態鑄造,然後不僅僅是C強制轉換爲正確的類: 所以,你可以做如下(非常錯誤的)結構。

+0

虛擬功能對內存有什麼影響?如果每個類只有一個實例被初始化,並且指向每個類的幾個指針會具有相同的影響,如果我有每個類的幾個實例(前提是函數以相同的速率訪問)? – User6897 2015-02-06 13:29:48

+0

我真的不想明確地施放任何東西,或者必須手動計算出類型,如果我可以避免它,因爲我想盡可能快地移動數組... – User6897 2015-02-06 13:44:19

+0

然後在對象內部使用虛函數或函子陣列你應該很好。 – MichaelCMS 2015-02-06 14:02:46

0

您需要多態性。在你的例子中,所有的類都有標準的方法。你需要讓它們變成虛擬的,所以可以應用多態。

class A { 
    virtual int aa(foo& f)const { return 1; } 
    virtual int dd()const { return 9; } 
}; 
class B : A { 
    virtual int aa(foo& f)const { return f.b; } 
}; 
class C : A { 
    virtual int aa(foo& f)const { return cc() + f.c - f.a; } 
    int cc()const { return 4; }// this doesn't need to be virtual because is not in the base class A 
}; 
class D : B { 
    virtual int dd()const { return 7; } 
}; 

以下是關於此主題的一些信息:http://www.cplusplus.com/doc/tutorial/polymorphism/。還有一些關於如何使用指針的信息。 我建議看看智能指針:http://www.cplusplus.com/reference/memory/shared_ptr/?kw=shared_ptr 另一個問題你應該看看是常量性:搜索「不變性C++」(不能發佈超過2個鏈接)

struct foo{ int a, b, c;const A* ptr; }; // const A* instead of A* 
+0

感謝您的鏈接! 這是否聲明一個const指針指向A或一個指向const A的指針? – User6897 2015-02-06 13:56:23

+0

在這裏你可以得到一些信息:http://www.codeguru.com/cpp/cpp/cpp_mfc/general/article.php/c6967/Constant-Pointers-and-Pointers-to-Constants.htm 這是一個指向常量A的指針 – Milan 2015-02-06 16:20:10

0

...我試圖解決無法將派生類型作爲派生類型存儲在基本類型的(值)數組中的問題。

可以店派生類型,作爲值,在數組中 - 你無法將它們存儲爲基礎類型的實例。

A union你的混凝土葉片類型幾乎是你想要的,但沒有辦法找出哪個工會的成員是生活的,或者使用多態派遣。

A 歧視聯盟是告訴你哪個成員是生活的,但不直接幫助調度。

Boost.Variant是一個特定的識別聯合提供了一個乾淨的機制,多態分派 - 不使用virtual,但使用與重載每個具體存儲類型的訪問者。在這種情況下,你甚至不需要存儲的類型與一個通用的抽象基礎相關 - 它們可以完全不相關。有關詳細信息,請在tutorial中查找apply_visitor