作为自我锻炼,我写了这个简单的代码:
#include <iostream>
int gIndex = 3;
template <class T> class Array
{
public:
explicit Array(int size);
T& operator[](int i) { return m_data[i]; }
T operator[](int i) const { return m_data[i]; }
T getAnchorPoint() const { return m_data[m_anchor]; }
private:
T* m_data;
int m_size;
int& m_anchor;
};
template <class T> Array<T>::Array(int size) : m_size(size), m_data(new T[size])
{
memset(m_data, 0, size*sizeof(T));
m_anchor = gIndex;
}
int main()
{
Array<double> a(10);
return 0;
}
我收到了编译错误,其中包含:
error C2758: 'Array<T>::m_anchor' : must be initialized in constructor base/member initializer list
它从未发生过,是什么让我提出这个问题:
是否必须在构造函数初始化列表中初始化任何类成员引用类型?
如果是这样,为什么?这是否与某种参考类型永远不能重新分配有关?
是否有更多类型必须在构造函数初始化列表中初始化?
答案 0 :(得分:14)
是否必须在构造函数初始化列表中初始化任何类成员引用类型?
是
如果是这样,为什么?是否与某种参考类型永远不能重新分配有关?
这就是原因的一部分。另一部分是因为必须初始化引用,并且它没有默认构造函数。
是否有更多类型必须在构造函数初始化列表中初始化?
任何没有赋值运算符(可以是复制或移动)或默认构造函数的类型。这显然包括(但不限于)const
成员,因为它们一旦构建就无法修改。
根据经验,你应该(几乎)总是喜欢在构造函数的初始化列表中初始化你的成员:为什么废弃循环首先默认构造一个对象然后只分配给它(如果这是可能的话),当你可以在第一时间正确地构建它吗?
答案 1 :(得分:4)
是否必须在构造函数初始化列表中初始化任何类成员引用类型?
是
这是否与某种参考类型永远不能被重新分配的事实相关?
是的,加上参考没有“null”或默认构造的事实。它是另一个对象的别名,它必须从一开始就绑定它。你不能这样做(这不在类定义中):
int main()
{
int& iref; // ERROR
int i = 42;
int& iref2 = i; // OK
}
因为iref
必须别名某事。
答案 2 :(得分:-1)
Must any class-member reference type be initialized in the constructor initialization list?
是的,我们应该始终使用初始化列表来初始化类的引用成员。
If so, why? Is that related somehow to the fact that a reference type can never be reassigned?
构造函数有两个阶段,即初始化和计算。因此,即使您不为数据成员使用初始化列表,编译器也会使用随机值初始化它。在计算阶段,通常以构造函数体的'{'开头,如果你做了一个赋值,那么编译器就会抱怨,因为引用成员已经初始化了。因此,您初始化此类成员的唯一机会是构造函数初始化列表。
Are there more types that must be initialized in constructor initialization list?
是的,const数据成员是您需要初始化列表的另一种类型。