= 和 {} 之间的区别,同时使用相同的构造函数参数名称初始化成员变量

difference between = and {} while initialising member variables using the same name for constructor arguments

根据这个 answer 对成员变量和构造函数参数使用相同的名称是可以的。所以在做了一些调试之后,我想通了为什么下面的代码不起作用(class 的操作成员从未被初始化导致 switch 语句失败。)

#include <cstdio>
#include <cstdlib>

enum class Operator {
    Add,
    Subtract,
    Multiply,
    Divide
};

class Calculator {
    Operator operation;
    public:
        Calculator(Operator operation) {
            operation = operation;
        }

        int calculate(int a, int b) {
            switch (operation) {
                case Operator::Add: {
                    return a+b;
                }
                case Operator::Subtract: {
                    return  abs(a-b);
                }
                case Operator::Multiply: {
                    return a*b;
                }
                case Operator::Divide: {
                    return a/b;
                }

            }
        }
};

int main() {
    Calculator calculator{Operator::Add};
    int a = 100;
    int b = 20;
    printf("%d + %d = %d\n", a, b, calculator.calculate(a, b));
}

在构造函数中用 operation{operation} 替换行 operation = operation 解决了这个问题,但我仍然不明白为什么 operation = operationoperation{operation} 相比产生了错误的结果,什么是两者在构造函数初始化上下文中的区别;

两个标识符相同的特殊情况下赋值和成员初始化的区别:

operation = operation; 是从参数 operation 到参数 operation 的赋值。参数 operation 使成员 operation.

黯然失色

要解决此问题,您必须编写 this->operation = operation;

class Calculator {
    Operator operation;
    public:
        Calculator(Operator operation) {
            this->operation = operation;
        }
};

除此之外,成员初始化operation(operation)operation{operation}更可取。

class Calculator {
    Operator operation;
    public:
        Calculator(Operator operation):
          operation{operation}
        {
        }
};

这是有效的,因为在成员初始化列表中,作用域(还)不包含参数列表(class 作用域)但是成员初始值设定项中的表达式在作用域中用参数解析(member功能范围)。


经过我草率的解释,我从cppreference.com:

中回忆起Constructors and member initializer lists

The body of a function definition of any constructor, before the opening brace of the compound statement, may include the member initializer list, whose syntax is the colon character :, followed by the comma-separated list of one or more member-initializers, each of which has the following syntax


class-or-identifier ( expression-list(optional) ) (1)


class-or-identifier brace-init-list (2) (since C++11)


parameter-pack ... (3) (since C++11)


1) Initializes the base or member named by class-or-identifier using direct initialization or, if expression-list is empty, value-initialization

2) Initializes the base or member named by class-or-identifier using list-initialization (which becomes value-initialization if the list is empty and aggregate-initialization when initializing an aggregate)

3) Initializes multiple bases using a pack expansion

  • class-or-identifier - any identifier, class name, or decltype expression that names a non-static data member, a direct or virtual base, or (for delegating constructors) the class itself

  • expression-list - possibly empty, comma-separated list of the parameters to pass to the constructor of the base or member

  • braced-init-list - brace-enclosed list of comma-separated initializers and nested braced-init-lists

  • parameter-pack - name of a variadic template parameter pack

即对于初始值设定项

  • 只有 class 标识符本身(对于委托构造函数调用)
  • base class 标识符(对于 base class 构造函数调用)
  • 和数据成员(对于成员初始值设定项)

被考虑但不考虑参数(任何名称)。

在成员初始值设定项(圆括号或大括号)内,成员函数的常用名称解析适用,因此,参数可能会覆盖同名成员。