c++ - 构造函数中这个奇怪的冒号成员 (": ") 语法是什么?

标签 c++ syntax constructor c++-faq ctor-initializer

最近我看到了一个像下面这样的例子:

#include <iostream>

class Foo {
public:
  int bar;
  Foo(int num): bar(num) {};
};

int main(void) {
  std::cout << Foo(42).bar << std::endl;
  return 0;
}

这个奇怪的 : bar(num) 是什么意思?它似乎以某种方式初始化了成员变量,但我以前从未见过这种语法。它看起来像一个函数/构造函数调用,但对于 int?对我来说没有意义。也许有人可以启发我。顺便问一下,是否还有像这样的任何其他深奥的语言功能,您永远不会在普通的 C++ 书籍中找到?

最佳答案

Foo(int num): bar(num)    

这种构造在 C++ 中称为成员初始化列表

简单地说,它初始化您的成员 bar 为值 num


构造函数中的初始化和赋值有什么区别?

成员初始化:

Foo(int num): bar(num) {};

成员分配:

Foo(int num)
{
   bar = num;
}

使用成员初始化器列表初始化成员与在构造函数体内为其赋值之间存在显着差异。

当您通过成员初始化列表初始化 字段时,构造函数将被调用一次,对象将在一次操作中构造和初始化。

如果您使用赋值,则字段将首先使用默认构造函数进行初始化,然后使用实际值重新分配(通过赋值运算符)。

如您所见,后者在创建和分配时会产生额外的开销,这对于用户定义的类来说可能相当可观。

Cost of Member Initialization = Object Construction 
Cost of Member Assignment = Object Construction + Assignment

后者实际上等同于:

Foo(int num) : bar() {bar = num;}

虽然前者等同于:

Foo(int num): bar(num){}

对于内置(您的代码示例)或 POD 类成员,没有实际开销。


什么时候必须使用成员初始化列表?

如果出现以下情况,您将不得不(而不是被迫)使用成员初始化列表:

  • 你的类(class)有引用成员
  • 你的类有一个非静态常量成员或者
  • 您的类成员没有默认构造函数或
  • 用于初始化基类成员或
  • 当构造函数的参数名称与数据成员相同时(这不是必须的)

代码示例:

class MyClass {
public:
  // Reference member, has to be Initialized in Member Initializer List
  int &i;
  int b;
  // Non static const member, must be Initialized in Member Initializer List
  const int k;

  // Constructor’s parameter name b is same as class data member
  // Other way is to use this->b to refer to data member
  MyClass(int a, int b, int c) : i(a), b(b), k(c) {
    // Without Member Initializer
    // this->b = b;
  }
};

class MyClass2 : public MyClass {
public:
  int p;
  int q;
  MyClass2(int x, int y, int z, int l, int m) : MyClass(x, y, z), p(l), q(m) {}
};

int main() {
  int x = 10;
  int y = 20;
  int z = 30;
  MyClass obj(x, y, z);

  int l = 40;
  int m = 50;
  MyClass2 obj2(x, y, z, l, m);

  return 0;
}
  • MyClass2 没有默认构造函数,因此必须通过成员初始化列表进行初始化。
  • 基类 MyClass 没有默认构造函数,因此要初始化其成员,需要使用成员初始化列表。

使用成员初始化器列表时要注意的要点:

类成员变量始终按照它们在类中声明的顺序进行初始化。

它们按照它们在成员初始化器列表中指定的顺序进行初始化。
总之,Member初始化列表不决定初始化顺序。

鉴于上述情况,始终保持成员初始化顺序与类定义中声明顺序相同的成员顺序始终是一个好习惯。这是因为如果这两个顺序不同,编译器不会发出警告,但相对较新的用户可能会将成员 Initializer 列表混淆为初始化顺序,并据此编写一些代码。

关于c++ - 构造函数中这个奇怪的冒号成员 (": ") 语法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55604285/

相关文章:

c++ -::* 在 C++ 中是什么意思?

javascript - 为什么我应该在javascript中的每个函数后使用分号?

javascript - 带条件重新分配的 ESLint 首选常量错误

javascript - UnCaught TypeError - Javascript 中的嵌套对象?为什么这是不允许的?对象字面量表示法有效

C++ 用户定义的空默认构造函数与隐式或默认默认构造函数

php - 开始 oop php 问题 : do constructors take the place of getter?

c++ - 为指针赋值

c++ - 等待 std::thread 完成

c++ - 将 void 指针转换为结构时无法获取值

该命令的语法批量不正确?