Jump to content
  • Advertisement
Sign in to follow this  
Evil Booger

How do I create a class constructor that initializes arrays of objects

This topic is 4052 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a class, EnemyShip, and I want to make an array of EnemyShip called smallShip like so: EnemyShip smallShip[3] But my compiler (MVSC++ EE) won’t allow that because “'EnemyShip' no default constructor to initialize arrays of objects.” So I tried to make a constructor for arrays like so: EnemyShip[] but my compiler won’t accept it because “empty attribute block is not allowed” I searched the forums and Google but I couldn’t find anything relevant. Please help. Thank you in advance.

Share this post


Link to post
Share on other sites
Advertisement
I'm assuming you are receiving Error C2539. All that is needed to create an array of objects is a default constructor (a constructor which takes no parameters). If you have defined a constructor for your EnemyShip object that takes parameters then the compiler will not generate a default one for you so you also need to define a default constructor.

From MSDN (http://msdn2.microsoft.com/en-us/library/41bws1hs(VS.80).aspx):
"new : 'class' : no default constructor to initialize arrays of objects

Initializing an array of objects requires a default constructor (a constructor with no parameters), which is called separately for each object in the array. The constructor was not available. If any constructor is defined, the compiler does not generate a default constructor and you must supply one."

Share this post


Link to post
Share on other sites
Is this what you are trying to do?

// allocate an array of 3 EnemyShips
EnemyShip* smallShip = new EnemyShip[3];



If it is, be sure to clean up the dynamically allocated memory when your done with those ships (like when you exit your app).

// free the memory
delete [] (smallShip);


Share this post


Link to post
Share on other sites
Wow thank you so much theNOOB it compiles now.

Haiduk67, I'm not allocating memory for them (new and delete don't like me) but thank you very much for replying.

Share this post


Link to post
Share on other sites
Or, just define a default constructor, if you've already defined your own constructor that accepts parameters. Something like this:

class Ship
{
private:
.
.
.
public:
Ship( your constructor parameters here )
Ship(); <---- Your default constructor
};



This would allow you to do what you want, but then you'll have to add some functions that allow you to set the class members for each Ship once you've created your array.

Share this post


Link to post
Share on other sites
Ok I have another question now. How do I make my inherited class "inherit" the deconstructor from the base class?

I know how to "inherit" the constructor:
derived_constructor_name (parameters) : base_constructor_name (parameters) {...}

but that doesn't work with the included "~" for the deconstructor.


Please help and thank you again for replying last time.

Share this post


Link to post
Share on other sites
Make sure that you are declaring your destructor as virtual if you plan to inherit from it.

Ex.

class EnemyShip
{
public:
EnemyShip();
virtual ~EnemyShip(); //<--This should be virtual if you want to inherit;

//...
};



That should solve ur problem...

Share this post


Link to post
Share on other sites
Yeah, you don't need to explicitly call your base class's destructor like you do the constructor - it'll get called for you automatically. The only catch is what TheN00B described - make the base class's constructor virtual - it's a good idea to do that or you might fall foul of one of the details of the way C++ works (specifically, when you 'delete x' it figures out which destructors to call by looking at the type of x, which might not actually be the type of the object it points to).

Share this post


Link to post
Share on other sites
OK, we need to clear up a few things here.

0) To make sure the previous stuff was fully understood: when the compiler says "'EnemyShip' no default constructor to initialize arrays of objects.", what that *means* is "because 'EnemyShip' does not have a default constructor, I can't make an array of them. You asked for an array, so I have to complain now." This is because, except in very limited circumstances*, each element of an array needs to be default-constructed.

* If the elements are not an object type, then of course they aren't default-constructed because there are no constructors. Also, we can use the brace-initialization syntax for arrays that are local variables, but *not* for members of a class, because it's an *initialization* syntax, and it's incompatible with the syntax of the initialization list.

So all you need is a default constructor of some sort. There is no such thing as a "constructor for arrays". Objects normally do not care about their containers, and actually it is generally a bad idea to make them aware of their containers.

Quote:
Original post by Evil Booger
Ok I have another question now. How do I make my inherited class "inherit" the deconstructor from the base class?

I know how to "inherit" the constructor:
derived_constructor_name (parameters) : base_constructor_name (parameters) {...}


First off, the term is "destructor", and not "deconstructor".

Next, this isn't really inheriting a constructor; it's initializing the "base part of" the derived object.

When an object is destructed, its members get destructed first, *automatically*. The reason you (sometimes) need to mention bases (base-parts-of) in a constructor initializer list is that there are multiple constructors to choose from, and the compiler can't choose for you. But because destructors never accept an argument, there can only be one for any class, which means there can only be one for each member (including bases)'s type, which means there is no decision to be made - the compiler just calls the appropriate destructors.

BUT, you will sometimes need to declare the base class' destructor to be 'virtual'. The reason for this is to make it behave polymorphically: if you 'delete' a pointer-to-Base that is actually pointing at a Derived object, and the destructor is not 'virtual', then no lookup is done. This means that the code never checks, at run-time, to figure out that the pointed-at thing is actually a Derived object. Which means that the wrong destructor gets called: i.e. the whole Derived object gets passed just to the code that is intended to destruct Base objects. This is NOT the same as "the Base part of the Derived object gets destructed, and the rest of the Derived object is left alone", and therefore it is NOT OK to do this when the rest of the Derived members don't have any special cleanup. It is undefined behaviour.

The rule of thumb is, if *any other member function* of the class will be virtual, ensure the destructor is, too. If that ever doesn't work for you, it's probably because you're doing something really strange that should be reworked anyway. This does mean that sometimes, you will declare and define an empty, virtual destructor in a base class (because you have to mark it, and in order to mark it you have to declare it; and since you declared it, the default one isn't generated, so you have to provide a definition too), and not override it in any derived classes. This is much better than having things seem to work for most of the project development cycle and then suddenly and mysteriously blow up before an important deadline. Undefined behaviour is kinda evil like that, you know.

When there are *no* "plain" virtual functions, though (and note that constructors, including copy constructors, and the assignment operator cannot be made virtual), there is no need to mark the destructor that way - and in fact, doing so can only hurt performance. With normal implementations, there is a once-per-class cost in object size that you pay for having virtual functions (including a destructor) - making one virtual is the same as making them all virtual.

Share this post


Link to post
Share on other sites
Quote:
The rule of thumb is, if *any other member function* of the class will be virtual, ensure the destructor is, too. If that ever doesn't work for you, it's probably because you're doing something really strange that should be reworked anyway.


Let's not forget:
http://en.wikipedia.org/wiki/Rule_of_three_(C++_programming)
and the assignment operator, copy constructor and self-assignment.

I mention this because of possible dynamic allocation.

Also, you're storing objects, not pointers to object. So as you pass objects around, there's a possibility that your EnemyShip objects will get copied, and, if they do some funny stuff, can possible multiply themselves within some other system.

Overall, there's really a lot of tiny details that you'll need to cover to make solid class.

All of which is conveniently covered here: http://www.parashift.com/c++-faq-lite/index.html

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!