When I run code that attempts to initialize an array of objects, and one has an invalid value, it doesn't seem to call the constructor, which would set a proper default value. The code below produces the output:
1
2
1528112104
Toy code:
#include <iostream>
using namespace std;
class BeeBoop
{
public:
static const int MIN_X = 1;
static const int MAX_X = 2;
BeeBoop(int x);
int getX() { return x; }
bool setX(int x);
private:
int x;
};
int main()
{
BeeBoop boops[] =
{
BeeBoop(1),
BeeBoop(2),
BeeBoop(3)
};
for (int i = 0; i < 3; i++)
cout << boops[i].getX() << endl;
}
BeeBoop::BeeBoop (int x)
{
if(!setX(x))
x = MIN_X;
}
bool BeeBoop::setX(int x)
{
if (x < MIN_X || x > MAX_X)
return false;
this->x = x;
return true;
}
Why isn't it calling the constructor and setting it to the default for BeeBoop(3)?
Even weirder, if I switch the order of the initialization list to
...
BeeBoop boops[] =
{
BeeBoop(1),
BeeBoop(3),
BeeBoop(2)
)
...
The output becomes:
1
0
2
So it initializes to 0, which is also not the default.
2 Answers 2
You're using the name x as both a function parameter and as a member variable (probably not a good idea!). Therefore you need to change:
BeeBoop::BeeBoop (int x)
{
if(!setX(x))
x = MIN_X;
}
to:
BeeBoop::BeeBoop (int x)
{
if(!setX(x))
this->x = MIN_X;
}
otherwise you're just modifying the parameter x rather than setting the member variable. (Alternatively you could just use unique names for parameters and member variables to avoid such ambiguities.)
Note that if you had compiled with suitable warnings enabled (-Wshadow) the compiler would have been able to point out your mistakes:
main.cpp: In constructor 'BeeBoop::BeeBoop(int)':
main.cpp:30:24: warning: declaration of 'x' shadows a member of 'BeeBoop' [-Wshadow]
BeeBoop::BeeBoop (int x)
^
main.cpp:14:13: note: shadowed declaration is here
int x;
^
main.cpp: In member function 'bool BeeBoop::setX(int)':
main.cpp:36:25: warning: declaration of 'x' shadows a member of 'BeeBoop' [-Wshadow]
bool BeeBoop::setX(int x)
^
main.cpp:14:13: note: shadowed declaration is here
int x;
1 Comment
Local variables of a class member function and function parameters are local variables hide data members of the class.
For example in the constructor parameter named x hides data member x
BeeBoop::BeeBoop (int x)
{
if(!setX(x))
x = MIN_X;
}
Thus in statement
x = MIN_X;
in the left side of the assignment there is used parameter x.
You should use either
BeeBoop::x = MIN_X;
or
this->x = MIN_X;
All functions where there exist the same problem have to be updated the same way.
Take into account that it is better to declare function getX with qualofoer const
int getX() const { return x; }
As the constructor of the class does not have specifier explicit then it is a conversion constructor. it means that you could write simply
BeeBoop boops[] = { 1, 2, 3 };
And function main could be simplified the following way:)
int main()
{
for ( BeeBoop b : { 1, 2, 3 } )
{
std::cout << b.getX() << std::endl;
}
}
The program output will be
1
2
1
this->x, but onlyx, and thereforethis->xis never initialized. Can you confirm?if(!setX(x))behaves differently depending on the value ofx, which has not been initialized. So technically it can any value. If your lucky it's0, in which case your code works, but that doesn't have to be.