2013-05-26 46 views
1

我想創建一個template <typename T> class InitConst,其中的一些成員是T的數組。我想在類的對象初始化期間填充這些數組,然後確保這些數組不會再發生變化,所以我爲每個這樣的數組定義了一個成員const T* const v(我知道第一個const指向元素,第二個指向元素指針)。在模板中初始化const常量數組C++類

對此做了實驗使我得出結論,定義「v」爲「const指向常量」,迫使我分配和填充相應的數組,然後最終用此數組的地址初始化「v」。而且,由於我不能在類「InitConst」的構造函數體內初始化「v」,所以我得出結論:我需要一個輔助函數,它的作用是(a)獲取構造函數參數,(b)分配和填充數組,(c)使用一些靜態指針來保存這些數組的地址。這些靜態指針將最終由構造用來初始化const的指針,所以我有這樣的代碼:

template <typename T> 
class InitConst 
    { 
    public: 
    const T* const v1; 
    const T* const v2; 
    const T* const v3; 

    InitConst(T a1, T a2, T a3, int n) 
    : v1(init(a1,a2,a3,n)), v2(init_p.temp_v2), v3(init_p.temp_v3) 
    { } 

    private: 
    struct Tinit { 
    T* temp_v1; 
    T* temp_v2; 
    T* temp_v3; 
    }; 
    static Tinit init_p; 

    T* init (T a1, T a2, T a3, int n) 
    { 
    init_p.temp_v1 = new T[n]; 
    init_p.temp_v2 = new T[n]; 
    init_p.temp_v3 = new T[n]; 
    // populate "temp_v1", "temp_v2" and "temp_v3" using the method's arguments. 
    return init_p.temp_v1; 
    } // End method init. 
    }; // End class InitConst. 

template <typename T> 
typename InitConst<T>::Tinit InitConst<T>::init_p; 

此代碼編譯和按預期工作,但我認爲這樣的設計扭曲:我習慣簡單的代碼,我首先分配一個數組,然後計算它的元素(這兩個東西通常發生在構造函數的主體中),然後使用該數組。與此相反,構造函數本身幾乎不做任何事情:它的角色轉移到方法「init」,它實際上創建了數組並使用一些輔助指針將它們傳回給構造函數。

然後我想:

一)這是設計(或類似的東西需要的),如果我決定做申報每個指針爲「常量指針爲const」,或者有一個更清潔的方式做到這一點? b)將每個指針聲明爲「const指向const」是一種防止濫用類的方法,但也許我不需要那麼多。一個稍微不嚴格的方法是將「v1」及其兄弟姐妹聲明爲私人成員,這樣他們就不能從班級之外改變。但是,這樣做也會阻止它們從課堂外讀取,並且我不希望每個「vx」陣列都有一個「read_vx」方法。那麼我能做些什麼呢,也就是說,什麼方法會導致更易讀的代碼,並且仍然保證至少數組不能從課外改變?

在此先感謝,並對長篇散文感到遺憾。

編輯:正如我在下面評論的那樣,在我的真實代碼中,我想要計算的各種數組更有效地計算在一起,這就是爲什麼我使用單個「init」函數的原因。我在示例中提供的「init」(「a1」,「a2」,「a3」)參數實際上是誤導人的。

+1

這可能是對代碼審查 –

+0

更好的設計更適合我的是避免裸指針和使用類型STL的。 – deepmax

+0

噢,謝謝:我不知道CodeReview,但我將來會用它來解決類似的問題。 –

回答

2

基於對問題的更新,您仍然可以乾淨地處理初始化,並比我之前提出的更進一步減少代碼。由於您的知道數據是可寫的,您可以使用const_cast並在構造函數中進行初始化。

template <typename T> 
class InitConst 
{ 
public: 
    const T* const v1; 
    const T* const v2; 
    const T* const v3; 

    InitConst(T a1, T a2, T a3, int n) 
     : v1(new T[n]), v2(new T[n]), v3(new T[n]) 
    { 
     T* t1 = const_cast<T*>(v1); 
     T* t2 = const_cast<T*>(v2); 
     T* t3 = const_cast<T*>(v3); 

     // do intialization here 
    } 
}; 



[注意:下面的解決方案是不能使用的基於從OP註釋]

這將是更好的有init協助在單個構件的初始化一次可變,而不是全部三個。這將顯着減少代碼,並且不需要static變量,這將需要定義每個類型的TInitConst一起使用。您還可以將init更改爲static以防止意外使用尚未初始化的成員變量。

template <typename T> 
class InitConst 
{ 
public: 
    const T* const v1; 
    const T* const v2; 
    const T* const v3; 

    InitConst(T a1, T a2, T a3, int n) 
     : v1(init(a1,n)), v2(init(a2,n)), v3(init(a3,n)) 
    { } 

private: 
    static const T* init (T a, int n) 
    { 
     T* v = new T[n]; 
     // populate "v" from "a" 
     return v 
    } 
}; 
+0

首先,感謝您的答案。實際上,我的真實代碼充滿了依賴關係(之前我沒有提到過):雖然我可以分別計算所有數組,但它們的計算效率要高得多,所以我只用一種方法計算它們。但關於「靜態」和「初始化」的提示確實適用,再次感謝! –

+0

如果您可以更新您的問題以包含有關依賴關係的信息,那麼可能會提供可用的解決方案。只需製作一份概要介紹階段的附錄。 –

+0

非常感謝,@隊長 - 彪悍! 'const_cast'功能非常強大,即使在我沒有在示例中提到的真實代碼的其他要求的情況下也足夠了。實際上,它非常強大,我現在意識到'const'關鍵字並沒有我想象的那麼強大。 –

0

沒有必要struct Tinit

tempalate<typename T> 
InitConst::InitConst(T a1, T a2, T a3, int n) 
    : v1(init(a1,n)), v2(init(a2,n)), v3(init(a3,n)) 
{} 

tempalate<typename T> 
T* InitConst::init (T a, int n) 
{ 
    T* result = new T[n]; 
    // TODO: populate result using a 
    return result 
}; 

// TODO implement destructor, copy constuctor and 
// copy assignement operator