Dan Jenson
Dan Jenson

Reputation: 1041

Error Initializing Object Array in C++

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.

Upvotes: 0

Views: 76

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311156

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

Upvotes: 0

Paul R
Paul R

Reputation: 213200

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;

Upvotes: 5

Related Questions