tags:

views:

610

answers:

7

Hi guys,

I'm just learning c++ coming from a Java background.

Just playing around with simple classes now, but for some reason the following won't compile, when the same syntax compiles fine elsewhere:

class CardDealer {

    private:
        string suits[4];
        string values[13];
        bool cardTaken[4][13];
        int getRand(int top);
        void getValidSuit(int *suit);
        void getValidCard(int suit,int *value);

    public:
        CardDealer();
        string dealCard();
        void resetDeck();
};

CardDealer::CardDealer(){
    suits = {"hearts", "clubs", "spades", "diamonds"};
    values = {"ace","two","three","four","five","six","seven","eight","nine","ten","jack","queen","king"};
    cardTaken = {{false,false,false,false,false,false,false,false,false,false,false,false,false},{false,false,false,false,false,false,false,false,false,false,false,false,false},
    {false,false,false,false,false,false,false,false,false,false,false,false,false},{false,false,false,false,false,false,false,false,false,false,false,false,false}};
}

obviously this is just a part of the class so please don't yell at me for missing '}'s

compiler chucks a wobbly when it hits the instantiations in the constructor, spits out errors like these:


1>.\CardDealer.cpp(26) : error C2059: syntax error : '{'
1>.\CardDealer.cpp(26) : error C2143: syntax error : missing ';' before '{'
1>.\CardDealer.cpp(26) : error C2143: syntax error : missing ';' before '}'
1>.\CardDealer.cpp(27) : error C2059: syntax error : '{'
1>.\CardDealer.cpp(27) : error C2143: syntax error : missing ';' before '{'
1>.\CardDealer.cpp(27) : error C2143: syntax error : missing ';' before '}'
1>.\CardDealer.cpp(28) : error C2059: syntax error : '{'

line 26 is the one where I've instantiated suits (suits = {...)

thanks for taking a look guys, much appreciated

A: 

Since we don't know your entire source file, we don't know what is in the lines 26,27,28. I am guessing the code:

cardTaken = {{false,.....

raises these errors. Instead of that very long initialization, you could use:

for(int i = 0; i<4; i++)
{
    for(int j = 0; j<13; j++)
    {
        cardTaken[i][j] = false;
    }
}

That way, your code is clearer and more understandable.

erelender
sorry for not being clearer, line 26 is where I've instantiated `suits`. edited post for clarity
Josh Bones
+3  A: 

I have corrected the earlier post:

You could initialise them like this outside the class:

namespace CardDealer
{
    static const string suits[] = {"hearts", "clubs", "spades", "diamonds"};
    static const string values[]={"ace","two","three","four","five","six","seven","eight","nine","ten","jack","queen","king"};

    class CardDealer 
    {    
    private:
        bool cardTaken[4][13];   
        ...
    };

    ...
}

In the constructor you could initialise cardTaken in a loop.

Indeera
I've just tried the above but the compiler gives the same errors. thanks anyway
Josh Bones
Only integral members can be initialised inside a class definition.
CiscoIPPhone
what do you mean by an integral member? as in an integer? or something else entirely...
Josh Bones
Yes, integers. This includes bool, char, wchar_t, signed and unsigned integer types.
CiscoIPPhone
+6  A: 

Until C++0x, you can only use the aggregate initializer syntax (ie, braces) when declaring an array.

Note that this program gives a similar error:

int thing[4];
int main ()
{
   thing = { 0, 1, 2, 3 };
}

You'll have to initialize your array with the somewhat tedious bracket syntax, one element at a time.

Dan Olson
ugh, thats nasty.I couldn't get it to work when initialising so I've had to go the one-at-a-time route. your right, extremely tedious.thanks!
Josh Bones
This isn't the only solution though, you can store the fixed initalizers in a separate array (perhaps an array of const char*) and simply copy them into the class instance variables with a single std::copy call in the constructor.
Charles Bailey
A: 

You could remove some of the tedium using something like this in your constructor.

const char* tempSuits[] = {"hearts", "clubs", "spades", "diamonds"};
for(int i=0; i<4; ++i) suits[i] = tempSuits[i];

You can use the curly brace syntax to initialise C-style strings, which you can then assign to std::strings.

You could also use the C-style strings in your class to begin with (then you wouldn't need the loop).

Nick
A: 

Simple solution:

class CardDealer {

    private:
        const string suits[4];
        const string values[13];
        bool cardTaken[4][13];
        int getRand(int top);
        void getValidSuit(int *suit);
        void getValidCard(int suit,int *value);

    public:
        CardDealer();
        string dealCard();
        void resetDeck();

    private:
        static string suits_initializer[4];
        static string values_initializer[13];
};


CardDealer::CardDealer(){
    memcpy(suits, suits_initializer, sizeof(suits));
    memcpy(values, values_initializer, sizeof(values));
    memset(cardTaken, 0, sizeof(cardTaken));
}

string CardDealer::suits_initializer[4] = {"a","b","c","d"};

this works, as long suits and values are constant.. but in fact, do you need these as instance variables? static suits, and static values are enough for you, in this example.

Yossarian
Using memcpy on class types such as std::string is very dangerous!
Charles Bailey
+1  A: 

The first question that arises is, do you need suits and values to be per-object arrays or can they shared between all instances of CardDealer?

If not, the I would make them static and then you can provide the static initialization syntax that you are trying to use at their point of definition.

E.g.

class CardDealer {

    private:
        static const std::string suits[4];
        static const std::string values[13];

    // ...
};

and in a .cc/.cpp file elsewhere:

const std::string CardDealer suits[4] = { "hearts", " ... ", ... };
const std::string CardDealer values[13] = { "ace", " ... ", ... };

If they do need to be per-class and these are just some initial values then I would prefer to make them a vector of strings an initialize them from some statically allocated C strings. e.g.:

class CardDealer {

    private:
        static const char* init_suits[4];
        static const char* init_values[13];

        std::vector<std::string> suits;
        std::vector<std::string> values;

    // ...
};

CardDealer::CardDealer()
    : suits( init_suits, init_suits + sizeof init_suits / sizeof init_suits[0] )
    , values( init_values, init_values + sizeof init_values / sizeof init_values[0] )
{
}

const char* CardDealer::init_suits[4] = { ... };
const char* CardDealer::init_values[13] = { ... };

As for your cardTaken array, as 0 converts to false you can just default-initialize the member in your constructor's initalizer list.

CardDealer::CardDealer()
    : suits( init_suits, init_suits + sizeof init_suits / sizeof init_suits[0] )
    , values( init_values, init_values + sizeof init_values / sizeof init_values[0] )
    , cardTaken()
{
}
Charles Bailey
A: 

You can use boost::assign :

#include <string>
#include <vector>
#include <boost/assign.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/assign/std/vector.hpp>

const std::vector<std::string> my_vector_of_strings = 
boost::assign::list_of("cat")("dog")("banana")("apple")(orange)("tuna")("salmon")("dinosaur")("blablabla")("...")("etc")("etc")("etc");

The fun thing is, you can declare stl containers as consts using this helpful library, since your arrays representing cards and values don't change, I'd probably declare them as consts anyway - and I'd use vectors as they're safer to use rather then a classic arrays are.

Maciek