Reputation: 626
As per this answer using same name for both member variable and constructor argument is fine. So after doing some debugging, I figured why the below code was not working (the operation member of the class was never getting initialized causing the switch statements to fail.)
#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));
}
replacing the line operation = operation
with operation{operation}
inside constructor fixed the issue, but I am still not getting why operation = operation
was producing wrong results compared to operation{operation}
and what's the difference between both in context of constructor initialization;
Upvotes: 1
Views: 110
Reputation: 20141
The difference between assignment and member initialization in the special case where both identifiers are identical:
operation = operation;
is an assignment from argument operation
to argument operation
. The argument operation
eclipses the member operation
.
To fix this, you had to write this->operation = operation;
.
class Calculator {
Operator operation;
public:
Calculator(Operator operation) {
this->operation = operation;
}
};
This aside, the member initialization operation(operation)
or operation{operation}
is preferrable.
class Calculator {
Operator operation;
public:
Calculator(Operator operation):
operation{operation}
{
}
};
This works because, in the member initialization list, the scope does not (yet) contain the argument list (class scope) but the expressions in the member initializers are resolved in the scope with arguments (member function scope).
After my sloppy explanation, I recalled Constructors and member initializer lists from cppreference.com
:
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
I.e. for initializers
are considered but not arguments (with any name).
Inside the member initializers (parentheses or curly braces), the usual name resolution of member functions applies and, hence, an argument may eclipse a member with same name.
Upvotes: 1