C++ 在初始化列表中初始化与在构造函数中初始化之间的区别

C++ 在初始化列表中初始化与在构造函数中初始化之间的区别,c++,C++,我不确定我的问题的标题是否正确,请随意更正。我认为: 在初始化列表中初始化相当于 inta=a 在构造函数中初始化相当于 inta;a=a 但我仍然无法找出以下输出的原因: #include <iostream> using namespace std; class test { int a,b; public: /* test(int a, int b): a(a), b(b) {} //OUTPUT: 3 2 test(

我不确定我的问题的标题是否正确,请随意更正。我认为:

  • 在初始化列表中初始化相当于
    inta=a

  • 在构造函数中初始化相当于
    inta;a=a

  • 但我仍然无法找出以下输出的原因:

    #include <iostream>
    using namespace std;
    
    class test
    {
        int a,b;
        public:
    
        /*
        test(int a, int b): a(a), b(b) {}         //OUTPUT: 3 2
        test(int a, int b) {   a = a; b = b;}     //OUTPUT: -2 1972965730
        test(int c, int d) {   a = c; b = d;}     //OUTPUT: 3 2 
        Hence it does work without this pointer. Unless the variable names are same
        */
    
        void print()    {   cout<<a<<" "<<b<<"\n";}
    };
    
    int main()
    {
        test A(3,2);
        A.print();
        return 0;
    }
    
    这是不对的。它对数据成员没有任何作用。应该是

    test(int a, int b) {   this->a = a; this->b = b;}
    
    这是不对的。它对数据成员没有任何作用。应该是

    test(int a, int b) {   this->a = a; this->b = b;}
    
    试着替换
    test(inta,intb){a=a;b=b;}
    with
    test(inta,intb){this->a=a;this->b=b;}
    我的编译器(msvc)生成所需的结果。

    尝试替换
    test(inta,intb){a=a;b=b;}
    with
    test(inta,intb){this->a=a;this->b=b;}

    我的编译器(msvc)生成所需的结果。

    每个函数都引入了一个新的作用域。当您将构造函数定义为

    test(int a, int b) { a = a; b = b; }
    
     test(int c, int d) { a = c; b = d; }
    
    隐藏类成员。编译器无法知道左边的
    a
    属于该类,右边的
    a
    是一个参数

    当您将构造函数声明为

    test(int a, int b) { a = a; b = b; }
    
     test(int c, int d) { a = c; b = d; }
    
    您没有这个问题,因为不再有命名冲突

    在建议的修复中,同样的推理适用:

    test(int a, int b) { this->a = a; this->b = b; }
    
    通过使用
    this
    指针明确限定lhs
    a
    是类成员,该指针隐式传递给每个成员函数,包括构造函数。但是,此代码并不等同于使用初始化列表初始化。你的问题是正确的:

  • 在初始化列表中初始化相当于
    inta=a
  • 在构造函数中初始化相当于
    inta;a=a
  • 如果您的成员变量是某个复杂的类,这将产生很大的不同。如果没有初始化列表,您将首先使用默认构造函数创建一个对象,然后复制并为其分配一个新值,而如果使用初始化列表,则只会发生复制构造

    因此,您应该始终更喜欢使用初始化列表:

    test(int a, int b): a(a), b(b) {}
    

    每个函数都引入了一个新的作用域。当您将构造函数定义为

    test(int a, int b) { a = a; b = b; }
    
     test(int c, int d) { a = c; b = d; }
    
    隐藏类成员。编译器无法知道左边的
    a
    属于该类,右边的
    a
    是一个参数

    当您将构造函数声明为

    test(int a, int b) { a = a; b = b; }
    
     test(int c, int d) { a = c; b = d; }
    
    您没有这个问题,因为不再有命名冲突

    在建议的修复中,同样的推理适用:

    test(int a, int b) { this->a = a; this->b = b; }
    
    通过使用
    this
    指针明确限定lhs
    a
    是类成员,该指针隐式传递给每个成员函数,包括构造函数。但是,此代码并不等同于使用初始化列表初始化。你的问题是正确的:

  • 在初始化列表中初始化相当于
    inta=a
  • 在构造函数中初始化相当于
    inta;a=a
  • 如果您的成员变量是某个复杂的类,这将产生很大的不同。如果没有初始化列表,您将首先使用默认构造函数创建一个对象,然后复制并为其分配一个新值,而如果使用初始化列表,则只会发生复制构造

    因此,您应该始终更喜欢使用初始化列表:

    test(int a, int b): a(a), b(b) {}
    

    在初始化列表中,语法是这样的:parens
    ()
    之外的每个变量名都是类成员。parens中包含的是作用域中发生的任何内容—无论是类成员还是构造函数参数。参数将隐藏类成员

    因此,您可以安全地执行以下操作:

    class MyClass
    {
        int i;
        MyClass(int i): i(i) {}
        //              ^-must be class member
    };
    
    编译器将正确地使用paren内部的参数来初始化paren外部的类成员

    paren中发生的事情与构造函数体中发生的事情具有相同的作用域

    因此:

    名为
    i
    的参数隐藏名为
    i
    的类成员,因此在构造函数体中永远不会访问该类成员

    您必须使用
    this
    明确消除歧义:

    class MyClass
    {
        int i;
        MyClass(int i)
        {
            // now we set class member i to parameter i
            this->i = i; 
        }
    }
    
    所有这些都在初始值设定项列表的语法中为您解决:

    初始化列表基本上是为您执行:
    this->i=i


    如果可能,您应该始终初始化初始化器列表中的成员。

    在初始化列表中,语法是这样的:parens
    ()
    之外的每个变量名都是类成员。parens中包含的是作用域中发生的任何内容—无论是类成员还是构造函数参数。参数将隐藏类成员

    因此,您可以安全地执行以下操作:

    class MyClass
    {
        int i;
        MyClass(int i): i(i) {}
        //              ^-must be class member
    };
    
    编译器将正确地使用paren内部的参数来初始化paren外部的类成员

    paren中发生的事情与构造函数体中发生的事情具有相同的作用域

    因此:

    名为
    i
    的参数隐藏名为
    i
    的类成员,因此在构造函数体中永远不会访问该类成员

    您必须使用
    this
    明确消除歧义:

    class MyClass
    {
        int i;
        MyClass(int i)
        {
            // now we set class member i to parameter i
            this->i = i; 
        }
    }
    
    所有这些都在初始值设定项列表的语法中为您解决:

    初始化列表基本上是为您执行:
    this->i=i


    如果可能,您应该始终初始化初始值设定项列表中的成员。

    有两个区别:在正文中给定值不是初始化,因为该值已初始化(基元类型除外)。在您的情况下,在第二个版本中,成员“a”被参数a遮蔽,但在初始化列表中它不是(因为您只能在初始化列表中初始化成员)。与
    a(a)
    i等效