2010-05-26 43 views
1

我有一個C++類模板,使指針數組。這也被typedef操作,使數組的數組等:遞歸C++模板與葉類做不同的事情的優雅方式?

typedef Array<Elem>   ElemArray; 
typedef Array<ElemArray>  ElemArrayArray; 
typedef Array<ElemArrayArray> ElemArrayArrayArray; 

我希望能夠通過複製指針,因此它們都指向同一個ELEM設置從另外一個葉節點。

但我也希望能夠從另一個設置一個數組(或數組陣列等)。在這種情況下,我不想複製指針,我想保持數組獨立和下降到每一個,直到我到達葉節點,在最終複製指針的地方。

我有這樣做的代碼(下面)。當你在一個數組中設置某些東西時,它會調用一個CopyIn方法來進行復制。

但是因爲這是模板化的,所以它還必須在葉類上調用CopyIn方法,這意味着我必須爲每個葉類添加一個虛擬方法,只返回false。

我也試着給模板添加一個標誌來告訴它它是否包含數組,以及是否調用CopyIn方法。這很好 - 葉節點的CopyIn方法永遠不會被調用,但它仍然需要在那裏才能編譯!

有沒有更好的方法來做到這一點?

#include <stdio.h> 

class Elem { 
public: 
    Elem(int v) : mI(v) {} 
    void Print() { printf("%d\n",mI); } 
    bool CopyIn(Elem *v) { return false; } 
    int mI; 
}; 

template < typename T > class Array { 
public: 
    Array(int size) : mB(0), mN(size) { 
    mB = new T* [size]; 
    for (int i=0; i<mN; i++) 
     mB[i] = new T(mN); 
    } 
    ~Array() { 
    for (int i=0; i<mN; i++) 
     delete mB[i]; 
    delete [] mB; 
    } 
    T* Get(int i) { return mB[i]; } 
    void Set(int i, T* v) { 
    if (! mB[i]->CopyIn(v)) { 
     // its not an array, so copy the pointer 
     mB[i] = v; 
    } 
    } 
    bool CopyIn(Array<T>* v) { 
    for (int i=0; i<mN; i++) { 
     if (v && i < v->mN) { 
     if (! mB[i]->CopyIn(v->mB[i])) { 
      // its not an array, so copy the pointer 
      mB[i] = v->mB[i]; 
     } 
     } 
     else { 
     mB[i] = 0; 
     } 
    } 
    return true; // we did the copy, no need to copy pointer 
    } 
    void Print() { 
    for (int i=0; i<mN; i++) { 
     printf("[%d] ",i); 
     mB[i]->Print(); 
    } 
    } 
private: 
    T **mB; 
    int mN; 
}; 

typedef Array<Elem>   ElemArray; 
typedef Array<ElemArray>  ElemArrayArray; 
typedef Array<ElemArrayArray> ElemArrayArrayArray; 

int main() { 
    ElemArrayArrayArray* a = new ElemArrayArrayArray(2); 
    ElemArrayArrayArray* b = new ElemArrayArrayArray(3); 

    // In this case I need to copy the pointer to the Elem into the ElemArrayArray 
    a->Get(0)->Get(0)->Set(0, b->Get(0)->Get(0)->Get(0)); 

    // in this case I need go down through a and b until I get the to Elems 
    // so I can copy the pointers 
    a->Set(1,b->Get(2)); 

    b->Get(0)->Get(0)->Get(0)->mI = 42; // this will also set a[0,0,0] 
    b->Get(2)->Get(1)->Get(1)->mI = 96; // this will also set a[1,1,1] 

    // should be 42,2, 2,2, 3,3, 3,96 
    a->Print(); 

} 
+0

我很難理解你想實現什麼。這意味着「從另一個設置一個X」是什麼意思? (我是非本土的,所以請原諒我,如果這是一個愚蠢的問題。) – sbi 2010-05-26 17:24:11

+0

你的'數組'類模板迫切需要一個拷貝構造函數和一個賦值操作符。根據[三項規則](http://en.wikipedia。org/wiki/Rule_of_three_%28C%2B%2B_programming%29),析構函數的存在暗示了這一點。我沒有看得更遠。 – sbi 2010-05-26 17:27:18

+0

「設置X從另一個」=我想要做的東西就像在這個例子中:a-> Set(1,b-> Get(2));它在b(2)的ArrayArray中將ArrayArray設置爲(1)。 我想重載賦值運算符,但我無法弄清楚如何去做,因爲我擁有的是指針,而不是對象。是否有重載的方式=所以p1 = p2不只是將指針p2分配給p1? – Costas 2010-05-26 17:36:34

回答

0

你可以使用模板特做一些與葉類不同:

template <> class Array<Elem> { 
    // Define how Array<Elem> should behave 
} 

正如在評論中提到別人,你真的應該考慮使用的operator []的而不是獲取和設置數組索引的方法。

+0

謝謝 - 這讓我看到了我可以用專業化做什麼,而且我覺得讓事情不那麼難看! – Costas 2010-05-27 08:00:41

0

我重新安排一下代碼,使用模板專業化,現在正常的設置做了深度複製像這樣:

void Set(int i, T* v) { mB[i]->CopyIn(v); } 

但包含葉數組必須添加專業化:

template <> void Array<Elem>::Set(int i, Elem* v) { SetPtr(i,v); } 

當然,你必須爲每個不同的葉類添加一個新的。至少如果你忘了這樣做,你會得到一個編譯器錯誤,因爲它無法在Elem類中找到CopyIn。

我想過用一個重載的賦值操作符替換CopyIn,但是如果忘記添加特化,這會失去編譯警告。

我也考慮過使用operator []而不是Get和Set(就這個例子而言),但是所有這些指針飛來飛去似乎有點危險 - 很容易寫一個[0]而不是(* a )[0]。此外,我無法解決將數組中的指針轉換爲返回[]的正確類型的參考所需的魔法(任何人都知道如何做到這一點?)。

#include <stdio.h> 

class Elem { 
public: 
    Elem(int v) : mI(v) {} 
    void Print() { printf("%d\n",mI); } 
    int mI; 
}; 

template < typename T > class Array { 
public: 
    Array(int size) : mB(0), mN(size) { 
    mB = new T* [size]; 
    for (int i=0; i<mN; i++) 
     mB[i] = new T(mN); 
    } 
    ~Array() { 
    for (int i=0; i<mN; i++) 
     delete mB[i]; 
    delete [] mB; 
    } 
    T* Get(int i) { return (i<mN) ? mB[i] : 0; } 
    void Set(int i, T* v)  { mB[i]->CopyIn(v); } 
    void SetPtr(int i, Elem* v) { mB[i] = v; } 
    bool CopyIn(Array<T>* v) { 
    for (int i=0; i<mN; i++) { 
     if (v && i < v->mN) { 
    Set(i, v->Get(i)); 
     } 
     else { 
     mB[i] = 0; 
     } 
    } 
    } 

    void Print() { 
    for (int i=0; i<mN; i++) { 
     printf("[%d] ",i); 
     mB[i]->Print(); 
    } 
    } 
private: 
    T** mB; 
    int mN; 
}; 


typedef Array<Elem>   ElemArray; 
typedef Array<ElemArray>  ElemArrayArray; 
typedef Array<ElemArrayArray> ElemArrayArrayArray; 

template <> void Array<Elem>::Set(int i, Elem* v) { SetPtr(i,v); } 

int main() { 
    ElemArrayArrayArray* a = new ElemArrayArrayArray(2); 
    ElemArrayArrayArray* b = new ElemArrayArrayArray(3); 

    // In this case I need to copy the pointer to the Elem into the ElemArrayArray 
    a->Get(0)->Get(0)->Set(0, b->Get(0)->Get(0)->Get(0)); 

    // in this case I need go down through a and b until I get the to Elems 
    // so I can copy the pointers 
    a->Set(1,b->Get(2)); 

    b->Get(0)->Get(0)->Get(0)->mI = 42; // this will also set a[0,0,0] 
    b->Get(2)->Get(1)->Get(1)->mI = 96; // this will also set a[1,1,1] 

    // should be 42,2, 2,2, 3,3, 3,96 
    a->Print(); 

} 
+0

好吧,我想出了[]返回,我只需要返回*(mB [i]);我的問題是我試圖返回不同的東西,如果邊界檢查失敗,當然我不能引發異常。 – Costas 2010-05-27 09:02:39