我想创建一个template <typename T> class InitConst
,其中一些成员是T
的数组。我想在类对象初始化期间填充这些数组,然后确保这些数组不会再更改,所以我为每个这样的数组定义了一个成员const T* const v
(我知道第一个常量指元素,第二个常量指指针(。
对此进行的实验使我得出结论,将"v"定义为"const指针到const"迫使我在最终用该数组的地址初始化"v"之前分配并填充相应的数组。此外,由于我无法在类"InitConst"的构造函数内部初始化"v",我得出结论,我需要一个辅助函数,其作用是(a(获取构造函数参数,(b(分配和填充数组,以及(c(使用一些静态指针来保存这些数组的地址。这些静态指针最终将被构造函数用来初始化常量指针,所以我得到了这样的代码:
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",该方法实际上创建了数组,并使用一些辅助指针将它们传递回构造函数。
然后我想知道:
a( 如果我决定将每个指针声明为"const-pointer-to-const",或者有更干净的方法,那么这种设计(或类似的设计(是必要的吗?
b( 将每个指针声明为"const-pointer-to-const"是防止类被滥用的一种方法,但也许我不需要那么多。一种稍微不那么严格的方法是将"v1"及其兄弟姐妹声明为私人成员,这样它们就不能从类外更改。然而,这样做也会防止从类外读取它们,并且我不希望每个数组"vx"都有一个"read_vx"方法。那么我该怎么办呢?也就是说,什么方法可以获得更可读的代码,并且至少可以保证数组不能从类外更改?
提前谢谢,很抱歉写了这么长的文章。
编辑:正如我在下面评论的那样,在我的真实代码中,我想要计算的各种数组可以更有效地计算在一起,这就是为什么我使用单个"init"函数。我在示例中提供的"init"("a1"、"a2"、"a3"(的参数实际上是误导性的。
根据问题的更新,您仍然可以干净地处理初始化,并比我之前提出的进一步减少代码。由于知道数据是可写的,因此可以使用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
变量的需要,该变量将需要为与InitConst
一起使用的每个类型的T
定义。您还可以将init
更改为静态,以防止意外使用尚未初始化的成员变量。
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
}
};
不需要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