C++ 初始化类构造函数中的成员

C++ 初始化类构造函数中的成员,c++,C++,有人能解释一下为什么我不能像在成员初始化列表中那样初始化构造函数体中的变量吗 class MyClass { public: MyClass(); virtual ~MyClass(void); private: std::string test; }; MyClass::MyClass() : test("asdf") <-- Case 1: This is OK { test("asdf"); <-- Case 2: This is

有人能解释一下为什么我不能像在成员初始化列表中那样初始化构造函数体中的变量吗

class MyClass
{
  public:
    MyClass();
    virtual ~MyClass(void);
  private:
    std::string test;
};

MyClass::MyClass()
: test("asdf")  <-- Case 1: This is OK
{
    test("asdf");   <-- Case 2: This is not
}
class-MyClass
{
公众:
MyClass();
虚拟~MyClass(void);
私人:
字符串测试;
};
MyClass::MyClass()
:test(“asdf”)语法在和之间变化,并在构造函数主体中为其赋值

在初始化列表中,它与您拥有的一样

MyClass::MyClass()
:test("abcd")
{
  //...
}
在正文中,可以使用赋值语法

test = "abcd"; 
语法
测试(“asdf”)
被解析为一个名为
test
的函数,该函数使用
参数“abcd”
调用

必须记住,如果成员没有默认构造函数,则初始化列表是正确构造成员的唯一位置。一旦构造函数的主体运行,所有成员都已以某种方式构造或初始化。如果可能的话,可以将它们分配给(例如,不适用于引用和
常量
成员等),但不能重新构造。

测试(“asdf”)是一个函数调用,您不能调用类似的字符串。初始化列表(“案例1”)是一种特殊情况

在构造函数体中,只需使用赋值

test="asdf".

在这种情况下,首先默认构造字符串测试(变为空),然后构造一个新字符串并将其分配给成员测试

在构造函数中初始化变量的方法如下:

class MyClass
{
public:
    MyClass();
    virtual ~MyClass(void);
private:
    std::string test;
};
方式1:

MyClass::MyClass() : test("asdf")
{
}
MyClass::MyClass()
{
    test = "asdf";
}
方式2:

MyClass::MyClass() : test("asdf")
{
}
MyClass::MyClass()
{
    test = "asdf";
}

无法初始化构造函数主体中的变量,因为构造函数主体在成员初始化列表中的所有基类和成员都已初始化之后运行。因为您没有在那里列出它们,所以它们被隐式默认初始化是不相关的


因此,在主体中,
test(“asdf”)尝试调用
测试上的
操作符()
,但失败。使用赋值(
test=“asdf”
)更改其值,或者最好直接在成员初始化列表中对其进行初始化。

您不能在构造函数体中初始化成员,因为此时它已经初始化,语法反映了这一事实。这已经得到了回答,但我想指出另一件事——不恰当地使用术语可能会导致错误的代码。所以有人说“您可以通过赋值在构造函数体中初始化”。为什么这是错误的?让我们看看这个例子:

class MyClass
{
  public:
    MyClass();
    virtual ~MyClass(void);
  private:
    std::string test;
};

MyClass::MyClass()
: test("asdf")  <-- Case 1: This is OK
{
    test("asdf");   <-- Case 2: This is not
}
struct foo {
    int i = 0;
    int &r = i;

    foo() {}
    foo( int &ref );
};
如果调用该ctor,则希望
r
指向与
ref
相同的位置:

foo::foo( int &ref ) : r( ref )
{
}
现在,如果您尝试通过赋值“初始化”,将会发生什么情况:

foo::foo( int &ref )
{
    r = ref;
}

因此,现在不再将
int
reference
r
指向与
ref
相同的
int
,而是将值赋给成员
i
。这可能会导致很难捕捉到bug,因为“术语在编程中很重要,您不应该随意使用它”

您不能将
test
作为函数调用。从技术上讲,这不是初始化,因为字符串是默认构造的。这是ctor主体内的分配。同意。更改了我的答案仍然听起来有误“如果你想初始化然后分配”,不,你不能那样初始化。虽然在本例中,结果在许多情况下都是相似的,但它不会工作,因为您不能以这种方式初始化。从技术上讲,这不是初始化,因为字符串在进入ctor主体之前由构造函数默认构造。它是ctor主体内的赋值。@是的,字符串是一个类,并在其自身构造函数中初始化。
test=“asdf”不是初始化。由于未使用成员初始化列表而调用构造函数时,字符串成员是默认构造的。然后在ctor主体中,您将执行赋值,而不是初始化。只有您的第一种方法使用
“test”
@NathanOliver初始化变量,您能举个例子吗?举个什么例子?前两个答案说明了同样的事情。初始化列表的另一个很好的属性是,它允许初始化const成员,根据定义,您无法更改这些成员。我会说“它们可能被分配到”,因为其中一些成员无法分配,仅初始化,例如reference。