1

C++ and Class

I have a class called “Sprite”, when this is initialized it takes a bool variable:

// constructor
Sprite::Sprite(bool type)
{ 
   // set stuff
}

// two Sprites of different types
Sprite Hero(1) 
Sprite Enemy(0)

Q. How do I initialize an array of 100 Sprites of type 0?

Sprite Enemies[100] ?

Harry Lime
  • 2,167
  • 8
  • 31
  • 53
  • 2
    Why the downvotes? I find this an interesting question. – TobiMcNamobi Oct 01 '13 at 12:50
  • 1
    I agree with @TobiMcNamobi !!, let's turn that frown upside down and give it some upvotes – Tom Swifty Oct 01 '13 at 12:56
  • 1
    On the other hand ... this looks like a duplicate of [C++: dynamically allocating a member array of structs using non-default constructor](http://stackoverflow.com/questions/6146025/c-dynamically-allocating-a-member-array-of-structs-using-non-default-construc) – TobiMcNamobi Oct 01 '13 at 13:01

7 Answers7

6

My suggestion is that you use a std::vector, and then use the constructor taking a value argument.

Like

std::vector<Sprite> Enemies(100, Sprite(false));

You might need proper copy-constructor and copy-assignment operators defined for Sprite for it to work.


If you don't have vectors (or std::array which might be better in your case), then you have to declare the array as a normal array, and then use a loop to initialize each entry:

Sprite Enemies[100];
for (size_t i = 0; i < 100; ++i)
    Enemies[i].set(false);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • many thanks - this is actually for an Arduino project though, not sure if Arduino has vectors -- I see somone has written their own: http://forum.arduino.cc/index.php/topic,45626.0.html not reall what I'm after though – Harry Lime Oct 01 '13 at 12:48
  • @JakeFrench If you are using a standard-conforming C++ compiler, there should be vectors. – Neil Kirk Oct 01 '13 at 12:50
  • just using the simple Arduino sketch – Harry Lime Oct 01 '13 at 12:51
  • @NeilKirk Sometimes on embedded processors due to space constraints projects are built with `-nostdlib` and so don't have the containers available to them by default. – RedX Oct 01 '13 at 13:02
  • @RedX Ah, interesting. But still, if this IS the case then the question should be tagged as "embedded" or whatever. – TobiMcNamobi Oct 01 '13 at 13:10
2

Unless I'm wrong, you cannot directly use constructor with parameters for object arrays. One solution is using a std::vector :

std::vector<Sprite> Ennemies(100, Sprite(false));
std::vector<Sprite> Ennemies(100, {false}); // C++11 style

If you really want C-style array, you can get it, by an example :

Sprite* pEnnemies = &Ennemies.front();

One other solution is using the new C++11 container std::array which is only a C-Style array in STL syntax :

std::array<Sprite, 100> Ennemies(Sprite(false));
Oragon Efreet
  • 1,114
  • 1
  • 8
  • 25
2

You can use a default constructor, that will simply default to the 0 value like this:

//default constructor
Sprite::Sprite()
{ 
  //set to false 
}

Sprite::Sprite(bool type)
{ 
   // set to type
}

Now Sprite Enemies[100] will work

Or with a little less code use a default value in the constructor like so:

Sprite::Sprite(bool type=false)
{
     //set to type
{
Tom Swifty
  • 2,864
  • 2
  • 16
  • 25
  • Then you can use something like `std::fill(Enemies, Enemies+100, Sprite(1));` if you need to set them all to true. – Nossidge Oct 01 '13 at 13:00
  • 1
    You should use initializer lists in preference of setting in the constructor body. – RedX Oct 01 '13 at 13:00
1

When creating an array of classes, they must be created by the default constructor.

You could add a default value "= false" for your type parameter, and then the code would work. It's not very flexible though, as you might want an array of the other type.

Another way is to allow your sprite to be reset after construction with a different type. After creating your array of blank sprites, call reset(type) on them in a for loop.

If you really need to use a non-default constructor on your elements, use std::vector. There are two ways to do it.

std::vector<Sprite> Enemies;
Enemies.reserve(100);
for (int i = 0; i < 100; i++)
{
    Enemies.push_back(Sprite(0));
}

or

std::vector<Sprite> Enemies(100, Sprite(0));
Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
1

For the sake of completeness, there is one last method using placement-new:

unsigned char data[sizeof(Sprite) * 100];
Sprite* ptr = reinterpret_cast<Sprite*>(&data[0]);
Sprite* end = ptr + 100;
for (; ptr != end; ++ptr)
    new (ptr) Sprite(0);

This is pretty much what the other answers, that don't rely on the copy-constructor use internally.

If Sprite has a non-trivial destructor you will have to call it explicitly using another loop at the end of data's lifetime:

Sprite* ptr = reinterpret_cast<Sprite*>(&data[0]);
Sprite* end = ptr + 100;
for (; ptr != end; ++ptr)
    ptr->~Sprite();
filmor
  • 30,840
  • 6
  • 50
  • 48
0

Use a default argument:

Sprite::Sprite(bool type=false) : mymember(type)
{}

and then when you declare:

Sprite Enemies[100];

it will call the default ctor for all 100 elements.

You should learn about member-initializer lists, the proper way to write a constructor in C++ is:

Sprite(bool type=false); // declaration

...
Sprite::Sprite(bool type) :  // definition
  x(random(0, 82)), 
  y(random(0, 20)),
  Ammo(25),
  Alive(true),
  Type(type)
{}
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
0

Many thanks all for taking a look, after reading comments I've found this works, overloading the constructor:

class Sprite
{
  public:
    Sprite();
    Sprite(bool type);
    void Move();
  private:
    unsigned int x, y, Ammo;
    bool Alive;
    bool Type;
};

// constructor
Sprite::Sprite()
{
  Alive = true;
  Type  = 0;
  Ammo  = 25;
  x = random(0, 82);
  y = random(0, 20);
}

Sprite::Sprite(bool type)
{
  Alive = true;
  Type  = 1;
  Ammo  = 25;
  x = 20; // get x from btn press
  y = 10; // get y from btn press
} 

Sprite Hero(1); Sprite Enemies[100];

Harry Lime
  • 2,167
  • 8
  • 31
  • 53