74

class C {
  T a;
public:
  C(T a): a(a) {;}
};

合法吗?

4

6 回答 6

65

是的,它是合法的,适用于所有平台。它将正确地将您的成员变量 a 初始化为传入的值 a。

一些更干净的人认为它们会以不同的方式命名,但不是全部。我个人实际上经常使用它:)

具有相同变量名的初始化列表有效,因为初始化列表中的初始化项的语法如下:

<成员>(<值>)

您可以通过创建一个执行此操作的简单程序来验证我上面写的内容:(它不会编译)

class  A
{

   A(int a)
   : a(5)//<--- try to initialize a non member variable to 5
   {
   }
};

您将收到类似的编译错误:A 没有名为“a”的字段。


附带说明:

您可能不想使用与参数名称相同的成员名称的一个原因是您更容易出现以下情况:

class  A
{

   A(int myVarriable)
   : myVariable(myVariable)//<--- Bug, there was a typo in the parameter name, myVariable will never be initialized properly
   {
   }
   int myVariable;
};

附注(2):

您可能希望使用与参数名称相同的成员名称的一个原因是您不太容易出现以下情况:

class  A
{

   A(int myVariable_)
   {
     //<-- do something with _myVariable, oops _myVariable wasn't initialized yet
     ...
     _myVariable = myVariable_;
   }
   int _myVariable;
};

这也可能发生在大型初始化列表中,并且您在初始化列表中初始化它之前使用 _myVariable。

于 2008-11-06T12:56:12.090 回答
34

可能导致有关此主题的混淆的一件事是编译器如何确定变量的优先级。例如,如果构造函数参数之一与类成员同名,则可以在初始化列表中编写以下内容:

MyClass(int a) : a(a)
{
}

但是上面的代码和这个有同样的效果吗?

MyClass(int a)
{
    a=a;
}

答案是不。每当您在构造函数的主体中键入“a”时,编译器将首先查找名为“a”的局部变量或构造函数参数,只有当它没有找到时,它才会开始寻找名为“a”的类成员(如果没有可用的,那么它将寻找一个名为“a”的全局变量,顺便说一句)。结果是上述语句“a=a”会将存储在参数“a”中的值分配给参数“a”,使其成为无用的语句。

为了将参数的值分配给类成员“a”,您需要通知编译器您正在引用此类实例中的值:

MyClass(int a)
{
    this->a=a;
}

很好,但是如果你做了这样的事情(注意没有一个叫做“a”的参数):

MyClass() : a(a)
{
}

好吧,在这种情况下,编译器会首先查找一个名为“a”的参数,当它发现没有任何参数时,它会将类成员“a”的值分配给类成员“a”,这实际上什么都不做.

最后,您应该知道您只能为初始化列表中的类成员赋值,因此以下将产生错误:

MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}
于 2011-10-12T13:37:53.970 回答
9

如果形参和成员的名称相同,请注意在构造函数中使用此指针来使用成员变量

class C {
  T a;
public:
  C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
于 2008-11-07T14:12:48.317 回答
4

法律:是的,正如 Brian 所解释的,编译器知道在初始化列表中期望的名称必须是成员(或基类),而不是其他任何东西。

好的风格:很可能不是——对于很多程序员(包括你,似乎)结果并不明显。为参数使用不同的名称将保持代码合法并同时使其成为良好的样式。

我宁愿写一些:

class C {
  T a_;
public:
  C(T a): a_(a) {}
};


class C {
 T a;
 public:
 C(T value): a(value) {}
};
于 2008-11-06T13:15:43.127 回答
2

这种做法的问题,虽然它可能是合法的,但编译器会在使用 -Wshadow 时考虑隐藏的变量,它会在其他代码中混淆这些警告。

此外,在非平凡的构造函数中,您会犯错误,忘记将 this-> 放在成员名称前面。

Java 甚至不允许这样做。这是不好的做法,应该避免。

于 2014-03-18T22:28:25.930 回答
0

嘿,伙计们,这是一个很好的问题。如果您想要字段和构造函数参数/方法参数的名称相同,则必须使用范围解析(::)运算符,或者您可以使用 this(this->)将参数值与成员映射,这样请仔细检查代码片段,您可以轻松理解。

class Student{
    private :
        string name;
        int rollNumber;

    public:
        Student()
        {
           // default constructor
        }

        // parameterized constructor
        Student(string name, int rollNumber)
        {
            this->name = name;
            Student::rollNumber = rollNumber;
        }

        void display()
        {
            cout<<"Name: "<<name <<endl;
            cout<<"Roll Number: "<<rollNumber<<endl;
        }

        void setName(string name)
        {
            this->name = name;
        }

        void setrollNumber(int rollNumber)
        {
            Student::rollNumber = rollNumber;
        }

};
于 2021-07-24T14:37:28.403 回答