为什么c++的初始化列表在大括号之前
why C++ Initialization list is before brace?
我想知道下面两个类有什么不同
示例1:
class A
{
string name;
public:
A(const char* _name):name(_name){}
void print(){cout<<"A's name:"<<name<<endl;}
};
示例2:
class A
{
string name;
public:
A(const char* _name){name(_name);}
void print(){cout<<"A's name:"<<name<<endl;}}
为什么例子1是通过的,最后一个是错误的?由于
在示例1中,您立即用给定的值初始化字符串。在示例2中,您首先创建一个空字符串,然后再分配它。
尽管存在一些性能差异,并且忽略了由于复制构造函数处理等原因而可能存在的差异,但本质上是相同的结果。
然而,一旦你使用const
成员,你将不得不使用示例1的方式来做到这一点,例如,我通常以以下方式创建唯一的id:
class SomeObject
{
static unsigned int nextID = 0;
const unsigned int ID;
SomeObject() : ID(nextID++)
{
// you can't change ID here anymore due to it being const
}
}
第一个例子是一个实际的初始化。它有许多优点,包括作为设置const
成员的唯一方法,以及具有适当的异常安全性。
第二个例子在c++中是无效的。如果你写的是name = name_
,那么这就是一个正常的赋值。当然,这并不总是可能的;对象可以是const
,也可以没有定义赋值操作符。这种方法也可能比第一个示例效率低,因为对象是默认初始化的和分配的。
对于,为什么初始化列表在构造函数体之前;这就是语言被定义的方式。
语言就是这样定义的。成员初始化式应该放在构造函数体之前。
在第一个示例中,使用以char *为参数的ctr初始化成员名
在第二种情况下,首先使用默认的ctr初始化,然后通过赋值操作符(operator=)获取值。这就是为什么你的情况是错误的,它已经在那里构造了,所以你不能再次使用ctr,你可以使用赋值操作符。
原因是名称查找在初始化器列表和函数体中的工作方式不同:
class A
{
std::string foo; // member name
public:
A(const char* foo) // argument name
: foo(foo) // member foo, followed by argument foo.
{
std::cout << foo; // argument foo.
}
};
如果初始化列表位于函数体内部,则成员foo
和实参foo
之间存在歧义。
初始化列表背后的动机是由于const字段按值保存对象(与引用/指针字段相反)。
这样的字段必须精确初始化一次(由于它们的const-ness)。如果c++没有初始化列表,那么一个actor将看起来像这样:
class A {
public:
const string s;
const string t;
A() {
// Access to either s or t is not allowed - they weren't initialized
s = "some-string";
// now you can access s but you can't access t
f(*this);
t = "some other string";
// From now you can access both ...
}
}
void f(A& a) {
// Can you access a.s or a.t?
cout << a.s << a.t;
}
如果没有初始化列表,则可以将A
类型的部分初始化对象传递给函数,而该函数将无法知道哪些字段已初始化。风险太大,编译器/链接器很难检查。
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 在C和C++中初始化结构中的数组
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 在函数内部的声明中初始化数组,并在外部使用它
- 继承:构造函数,初始化C++11中基类的类C数组成员