views:

127

answers:

5

Forgive me if I'm just blatantly missing something, but I'm trying to make the transition from structs and c to classes and c++.

Heres what I'm trying to do:

A have a "Checkers" class and a "Board" class.

Now with structs, I could just create an array of Checkers in my "board.cpp" file by doing:

Checker checkers[2][12]

(0 and 1 for each side, 0-11 for each piece)

The problem is that with classes, doing the same declaration will attempt to call the "Checkers" constructor. I get this error: "error: no matching function for call to ‘Checker::Checker()’"

My Checker constructor deals with initializing an individual piece (like if it is on side 0 or 1, piece 0-11), so I didnt mean to call it there.

Is there a way to avoid this, or am I going about this the wrong way? Thanks.

EDIT: Or maybe I should just design the constructor to initialize an array of checkers? Can you even declare variables as a datatype of a class/object?

+3  A: 

The problem is that with classes, doing the same declaration will attempt to call the "Checkers" constructor. I get this error: "error: no matching function for call to ‘Checker::Checker()’"

If you have defined parameterized constructors for your class(and not defined the default constructor), the default constructor won't be provided by the compiler. You have to write your version of default constructor as well.

Instead of using a two dimensional array, use vector of vectors.

std::vector<std::vector<Checker> > checkers;
Prasoon Saurav
@Downvoter: Please tell me the reason.This is unbelievable, two downvotes for no reason. x-(
Prasoon Saurav
+1 back to 0. Look at the bright side, you gained (2 * 10) - (2 * 2) = 16 rep!
Daniel
Not me. But I at tempted to give you another down vote. Why use vectors? The size of the array is static and not dynamically allocated. Bad advice. Writing a default constructor is not going to help the problem (just hide it).
Martin York
@Daniel: Frankly speaking I don't care much about reputation(we are all here to learn) but I could not understand why my answer was downvoted. There was nothing so _bad_ about the answer.
Prasoon Saurav
@Martin: The size is known at compile time thats perfectly fine. I just recommended what I should have. Arrays are evil you better know it and as far as the default constructor is concerned, what if he creates another Checker object with no parameter?He has to define it then.:-)
Prasoon Saurav
@Prasoon: The vector also uses the default constructor. So it is no more usefull in that context than an array.
Martin York
+2  A: 

Create a default constructor. Then use an initial function. I do recomend you use STL vector.

Charles Beattie
So, don't do anything in the Checkers constructor, and initialize the values later?
kevin
Both above suggestions are bad. A default constructor will not solve the problem it will hide the problem. It requires a re-thinking of how the class works. vector is good for dynamically resizeable arrays but the size is known at compile time (and not dynamically allocated )so there is no reason to use a vector.
Martin York
There is one reason to use a vector - if your library implements it, you get bounds checking. (assuming you don't want to import any other bounds checked array class). But otherwise yes.
Pete Kirkham
Actually vector (normal usage) does __NOT__ have bounds checking. You specifically need to use the bounds checked API 'at(X)'. If we are talking debug mode then yes vectors can have a debug version of the STL that implements bounds checking but the compiler is just as likely to do bounds checking of arrays (when possable) in this situation.
Martin York
I agree with Martin - C++ may have some high level functionality in it's libraries, but it still has low level fragility in a lot of cases. The result of an out-of-bounds access to a vector is officially undefined, no different to an array - you only get an exception throw if you have something *more* than just C++, and you can get stuff to do that for ordinary C arrays too (there is a product *called* Boundschecker). BTW - this includes iterator-based access - vector iterators can, in typical C++ implementations, be moved well out of bounds of the vector.
Steve314
Although, come to thing of it, checkers can be taken. There won't always be twelve checkers for each player. A vector implementation allows for this without requiring the Checker class to support a dummy value. Creating the two vectors of checkers empty also solves the constructor problem - no default constructor needed as no checker gets default-constructed.
Steve314
+5  A: 

You can either create a default constructor or have an array of Checker pointers and initialize them by dynamically allocation each Checker in the Board's constructor with the appropriate parameters. In the latter case, the constructor is not called until you allocate them.

Max Shawabkeh
A: 

To answer this, I really need to see the definition of the "Checker" class. Here's a guess, though...

I think your Checker class defines non-default constructors, but doesn't have a default constructor. There is a default default constructor IYSWIM, but as soon as you define any constructor for yourself the compiler-provided implicit default constructor is disabled.

If you have...

class Checker
{
  public:
    Checker (int p)  {  ...  };
};

You cannot use the default constructor, as needed for...

Checker checkers[2][12];

Instead, try...

class Checker
{
  public:
    Checker ()  {  ...  };
    Checker (int p)  {  ...  };
};

As for the advice to use std::vector, in this case I disagree. The array is fixes size, so there is no benefit to using std::vector - only extra complexity and other costs.

Keep your C-style array, but make it private (or at least protected) within a "Board" class is my advice.

Steve314
+1  A: 

You are creating an array of checkers to represent the individual checkers belonging to each side. The checkers require you to tell which side the checker is on, and which checker it is.

Why do you need to know which checker is which? If a player went out of the room, and someone swapped two of his checkers over, would he notice?

You can pass one constructor argument using array syntax as follows:

enum Side { White, Black };

class Checker
{
    Side side ;
public:
    Checker ( Side side ) : side(side) {
    }
};


int main()
{
    Checker white[12] = { White, White, White, White, White, White, White, White, White, White, White, White, };
    Checker black[12] = { Black, Black, Black, Black, Black, Black, Black, Black, Black, Black, Black, Black, };
    Checker* both[2] = { white, black };

    return 0;
}

Multiple arguments require a copy constructor and would look like:

    Checker white[12] = { Checker(White,0), Checker(White,1) ...

But I'd tend to just add the checkers to the board using just a few checker objects, representing White, Black, White Queen and Black Queen instead, unless there is a very good reason for identity to be tracked.

Pete Kirkham
I have individual numbers for each checker piece because thats how I display the board and get user input for which piece to move
kevin