C++ 类成员初始化差异
关于复数的类定义,我看到了两种类型的定义: 定义1C++ 类成员初始化差异,c++,C++,关于复数的类定义,我看到了两种类型的定义: 定义1 class Complex { private: double re; double im; public: Complex(float r,float i) {re = r; im = i;} ~Complex() {}; }; 定义2 class Complex { private: double re; double im; public
class Complex
{
private:
double re;
double im;
public:
Complex(float r,float i) {re = r; im = i;}
~Complex() {};
};
定义2
class Complex
{
private:
double re;
double im;
public:
Complex(double r,double i): re(r), im(i) {}
~Complex() {};
};
第一个定义在我看来还可以,但我不太理解第二个定义,它是如何定义的
Complex(double r,double i): re(r), im(i) {}
工作?“re()”是什么意思 这是一个初始化列表。它将
re
的值设置为r
,将im
的值设置为i
通常使用初始化列表来查看性能增益,但知道何时不使用它也是很重要的。
< P>首先,在C++中的整个类定义之后应该有分号。否则,您的代码将很容易编译 不管怎样Complex(double r,double i): re(r), im(i) {}
是一个复杂类的构造函数,它只将r的值放入re,将i的值放入im。这是初始化类值的另一种方法
请注意,这样的初始化列表对于初始化类中的成员类非常有用。下面是一个例子:
class MemberClass
{
private:
int mValue;
public:
MemberClass(int value): mValue(value) {}
};
class MemberHolder
{
private:
MemberClass mMember;
public:
MemberHolder(int value): mMember(value) {}
};
初始化列表对于在其他类中使用没有默认构造函数的类很重要。复杂的
构造函数的第二种形式使用的是不同的(和)初始化类成员
re(…)
意味着成员字段re
应该用传递的任何参数构造
作为另一个示例,您可以创建基本体,如double
和int
,如下所示:
double d(5.0d);
int i(5);
这应该可以解释括号在列表中的作用。它被称为初始值设定项列表。在类的构造函数中,可以使用此语法初始化成员变量。所以在这里,它相当于把语句re=r;im=i构造函数主体中的代码>
对于POD变量,如int
、double
和指针类型,初始值设定项列表语法和正文中的常规赋值之间没有区别。但是,对于const
变量、引用和具有非平凡构造函数的对象,有一个重要的区别:
- 对于
const
变量和引用变量,它们必须在初始值设定项列表中初始化。不能通过在正文中为它们赋值来初始化它们
- 对于具有非平凡构造函数的对象,在初始值设定项列表中初始化它们的方式与调用的构造函数相对应。如果省略变量,则调用该对象的默认构造函数(如果该对象没有默认构造函数,则这是编译器错误)
因此,通常建议在初始值设定项列表中初始化具有构造函数的对象,以避免重复工作——如果您通过从初始值设定项列表中忽略它来运行其默认构造函数,然后在构造函数体中执行某种初始化,那么您将对其进行两次初始化,这可能是浪费
例如:
class Example
{
private:
std::string m_string;
public:
Example()
{
// m_string is first initialized by the std::string default constructor,
// then we assign to it with operator=(const char *).
// This is inefficient.
m_string = "test";
}
Example(int dummy)
: m_string("test")
{
// Better: we just call the std::string(const char*) constructor directly
}
};
在C++中,赋值和初始化之间有区别。
a = 5; // assignment
int b = 6; // initialization
int b(6); // also initialization
类的第一个版本在构造函数体中执行赋值。这会更加昂贵,因为数据成员re
和im
首先是默认构造的,然后分配它们的值
在第二个版本中,使用构造函数初始化列表。在这里,使用提供的值初始化数据成员。这发生在一个步骤中,而默认构造函数+赋值是两个步骤。这样更有效
通常,您应该更喜欢在初始化列表中初始化数据成员,而不是在构造函数体中分配它们的值。不过有一个警告。初始化列表中的数据成员按照它们在类中声明的顺序初始化,而不是按照它们在初始化列表中出现的顺序初始化。通常,您希望列表中成员的顺序与其声明的顺序相匹配。否则,如果一个数据成员的初始化取决于另一个数据成员的值,那么您可能最终会遇到很难找到的bug