2010-05-26 53 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