在内部和关于生成的代码之间,是否有真正的区别:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
和
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
谢谢...
在内部和关于生成的代码之间,是否有真正的区别:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
和
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
谢谢...
您需要使用初始化列表来初始化常量成员、引用和基类
当您需要初始化常量成员、引用并将参数传递给基类构造函数时,如注释中所述,您需要使用初始化列表。
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
示例(非详尽)类/结构包含参考:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
以及初始化需要参数的基类的示例(例如,没有默认构造函数):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
假设这些值是原始类型,那么不,没有区别。初始化列表仅在您将对象作为成员时才会有所不同,因为初始化列表不是使用默认初始化然后赋值,而是允许您将对象初始化为其最终值。这实际上可以明显更快。
是的。在第一种情况下,您可以将 和 声明_capacity
为_data
常量_len
:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
如果您想const
在运行时计算它们的值时确保这些实例变量的特性,这将很重要,例如:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
实例必须在初始化器列表中初始化,或者基础类型必须提供公共无参数构造函数(原始类型会这样做)。
我认为这个链接http://www.cplusplus.com/forum/articles/17820/给出了一个很好的解释——尤其是对于那些刚接触 C++ 的人。
初始化器列表更有效的原因是在构造函数体内,只发生了赋值,而不是初始化。因此,如果您正在处理非内置类型,则该对象的默认构造函数在输入构造函数的主体之前已经被调用。在构造函数体内,您正在为该对象分配一个值。
实际上,这是对默认构造函数的调用,然后是对复制赋值运算符的调用。初始化列表允许您直接调用复制构造函数,这有时会明显更快(请记住,初始化列表在构造函数的主体之前)
我要补充一点,如果您的类类型成员没有可用的默认构造函数,那么初始化是构造类的唯一方法。
一个很大的区别是赋值可以初始化父类的成员;初始化器仅适用于在当前类范围内声明的成员。
取决于涉及的类型。之间的区别是相似的
std::string a;
a = "hai";
和
std::string a("hai");
第二种形式是初始化列表——也就是说,如果类型需要构造函数参数或者使用构造函数参数更有效,它会有所不同。
真正的区别归结为 gcc 编译器如何生成机器代码并放置内存。解释:
当然还有其他方法可以处理 const 类型成员。但是为了让他们的生活更轻松,gcc 编译器作者决定设置一些规则
只有一种方法可以初始化基类实例和非静态成员变量,那就是使用初始化列表。
如果您没有在构造函数的初始化列表中指定基类或非静态成员变量,则该成员或基类将被默认初始化(如果成员/基类是非 POD 类类型或非 POD 类的数组类型)或未初始化,否则。
一旦进入构造函数主体,所有基类或成员都将被初始化或未初始化(即它们将具有不确定的值)。构造函数体中没有机会影响它们的初始化方式。
您可以将新值分配给构造函数主体中的成员,但不能分配给不可分配的const
成员或类类型的成员,并且无法重新绑定引用。
对于内置类型和一些用户定义的类型,在构造函数主体中赋值可能与在初始化列表中使用相同值进行初始化具有完全相同的效果。
如果您未能在初始值设定项列表中命名成员或基,并且该实体是引用,具有没有可访问的用户声明的默认构造函数的类类型,是const
合格的并且具有 POD 类型,或者是 POD 类类型或 POD 类类型的数组包含const
合格的成员(直接或间接),则程序格式错误。
如果你写一个初始化列表,你就一步完成;如果您不编写初始化程序列表,您将执行 2 个步骤:一个用于声明,一个用于分配值。
构造函数中的初始化列表和初始化语句是有区别的。让我们考虑下面的代码:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
当使用 MyClass 时,所有成员将在构造函数中的第一条语句执行之前初始化。
但是,当使用 MyClass2 时,在执行构造函数中的第一条语句时,所有成员都没有初始化。
在后面的情况下,当有人在某个成员初始化之前在构造函数中添加了一些代码时,可能会出现回归问题。
这是我没有看到其他人提到的一点:
class temp{
public:
temp(int var);
};
temp 类没有默认 ctor。当我们在另一个类中使用它时,如下所示:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
代码不会编译,因为编译器不知道如何初始化obj
,因为它只有一个显式的 ctor 接收一个 int 值,所以我们必须改变 ctor 如下:
mainClass(int sth):obj(sth){}
所以,它不仅仅是关于 const 和引用!