Page 2 of 2
Posted: Mon Sep 17, 2007 5:37 am
by Solar
Zacariaz wrote:i never really understod the use of "static"...
Probably because there's about a dozen different meanings to the keyword... stating from memory:
- A static function will be visible only in its current translation unit (equivalent to the C++ anonymous namespace);
- A static member function will be local to the class, not to individual instances (i.e., you can call it as Class::function() without having a Class object at hand, and it can access only static members);
- A static data member will also be local to the class, not to individual instances (i.e., your Value / Set arrays would be stored once with the class, not individually for each instance, which is what you want);
- A static variable inside a function will be initialized on first call to the function only, and retain its value across subsequent calls to the function.
There are more ways to use static, but these are the ones I use regularily and can remember ad hoc.
...and originally i didnt think they would be visible outside the constructor, but i got the impression from your code that they would.
Note the placement in my first code example; they are class variables, not local to the constructor.
So, how to initilize them the smart way outside the constructor?
I mean i can declare a variable, but not initialize it outside the constructor, as far as i know.
Oops... I just realized my first code example does not compile correctly. You initialize them like this:
Code: Select all
class Foo {
static char const bar[];
};
char const Foo::bar[] = "ABCDEF...";
but i still need access to card_t::V and card_t::S from deck...
No you don't. The larger your project, the mroe important it is to make your coding follow the abstraction, not the other way round. Trust me on this.
So, the alternative is to make functions in card_t for just about everything and only let deck be handling the order of the cards, and not having anything to do with what they actually contain. (this would probably be the right way to go however)
Correct.
I have never done much OOP programming so excuse me if im asking some stupid questions. I have allready learned alot and i hope to learn alot more.
Since you are taking all this in exceptionally good grace, it is actually fun to help you with this. You're very welcome.
Posted: Mon Sep 17, 2007 5:41 am
by Zacariaz
NB: this part of the post wasnt posted when i answered
Code: Select all
/* Sorry for insisting with the naming... you will find this is a
very common notation style. */
class Card
{
public:
Card( char const value, char const set ) : mValue( value ), mSet( set );
char value() const { return mValue; }
char set() const { return mSet; }
private:
char mValue;
char mSet;
};
I believe it is more or less consistent with the code in my answer, but what with all the "const" definitions?
(dang, i need one of those really thick book where you can read everything about anything)
Posted: Mon Sep 17, 2007 5:44 am
by Solar
Zacariaz wrote:what with all the "const" definitions?
A "const" after the parameter list of a member function means this function can be called for a constant
instance of a class (i.e., you "promise" that you don't change any member variables in this function).
Zacariaz wrote:(dang, i need one of those really thick book where you can read everything about anything)
Stroustrup, "The C++ Programming Language". Oh, and 5+ years experience as a pro C++ maintenance coder.
Posted: Mon Sep 17, 2007 5:56 am
by Zacariaz
edit:
Posted: Mon Sep 17, 2007 6:04 am
by Zacariaz
edit:
Posted: Mon Sep 17, 2007 6:05 am
by Solar
Zacariaz wrote:phew we are talking past each other here
Feel free to point out where exactly.
Should include it all (except the shuffle function) and be correctly coded... well, i compiles allright
Unfortunately it doesn't.
You have ignored my last post on the initialization of statics. The V / S you initialize in the constructor is not the same as the V / S declared as static class members. You will get a linker error as soon as you try to access card_t::V[] the first time.
(Compiling with -Wall -Wextra would have given you warnings about "unused variable V / S" in the constructor.)
There are two more warnings about using a char subscript in an array (in getv() / gets()), but those can be resolved by an explicit cast.
Edit: I see you found the linker error.
Edit 2: ..._t is C style, and highly unusual to be used as a C++ class name.
Posted: Mon Sep 17, 2007 6:08 am
by Zacariaz
yes, i was too fast with it, but what you are saying is simply that i have to have: const char card_t::V[] = "A23456789TJQK"; outside the class? I prefer to have it contained inside the class
about edit:2
well maybe it is, but it works very well for me. i guess if it is so unusual i will stop doing it someday
This works without any problems. Wrote a little print thingy just to test:
Code: Select all
#include <vector>
class card_t {
char Value,Suit;
static const char V[];
static const char S[];
public:
card_t(const char v,const char s):Value(v),Suit(s) {}
char getv() const {return V[Value];}
char gets() const {return S[Suit];}
char get() const {return Value<<2|Suit;}
};
const char card_t::V[] = "A23456789TJQK"; // Do they have to be there?
const char card_t::S[] = "cdhs"; // Looks wrong, just wrong! ;-)
class deck_t {
std::vector<card_t> Deck;
public:
deck_t() {
for(int s = 0; s < 4; s++)
for(int v = 0; v < 13; v++)
Deck.push_back(card_t(v,s));
}
void shuffle() {}
void print() {
for(int i = 0; i < 52; i++) {
std::cout << Deck[i].getv() << Deck[i].gets() << std::endl;
}
}
};
Posted: Mon Sep 17, 2007 6:29 am
by Solar
Zacariaz wrote:what you are saying is simply that i have to have: const char card_t::V[] = "A23456789TJQK"; outside the class? I prefer to have it contained inside the class
Well, eventually you will split up your code into multiple files - for each class one .hpp file containing the class
declaration, and one .cpp file containing the
definition. The latter is where the
definition of the array goes. (
Not the header, or you will end up with a copy of the array in
every translation unit that included the header...)
Code: Select all
const char card_t::S[] = "cdhs"; // Looks wrong, just wrong! ;-)
To get back to your ASCII "hack", try this:
Code: Select all
const char card_t::S[] = { 5, 4, 3, 6 };
Voila, you got your ASCII chars back.
Posted: Mon Sep 17, 2007 6:34 am
by Zacariaz
Solar wrote:Code: Select all
const char card_t::S[] = "cdhs"; // Looks wrong, just wrong! ;-)
To get back to your ASCII "hack", try this:
Code: Select all
const char card_t::S[] = { 5, 4, 3, 6 };
Voila, you got your ASCII chars back.
I was wondering how, but that was not what i meant by it
what i ment was simply that it shouldnt be outside the class.
anyway, im strugling with the shuffle thingy now, cant remember how to create a proper rand(), but i seem to remember having asked not so long ago, so it shouldnt be hard to find it again...
Posted: Mon Sep 17, 2007 7:04 am
by Zacariaz
You said that random_shuffle() cpuld take a third argument. Maybe i misinterpeted it, because i cant get it to take a third argument, however, when calling srand(time(0)) it has an effect.
Is this what you ment?
Posted: Mon Sep 17, 2007 7:27 am
by Solar
Have you checked whatever you use as reference for the documentation of random_shuffle()? You
do know what a functor is?
Paraphrased from
Dinkumware.com, more precisely
the random_shuffle() doc:
Code: Select all
template<class RanIt, class Fn1>
void random_shuffle(RanIt first, RanIt last, Fn1& func);
The template function evaluates swap(*(first + N), *(first + M)) once for each N in the range [1, last - first), where M is a value from (Diff)func((Diff)N), where Diff is the type iterator_traits<RanIt>::difference_type.
What that means (grossly simplified): You write a function, which takes an int N as parameter, and spits out a random number in the range [0,N]. Let's say that function is called my_random( int n ), then the call would look like this:
Code: Select all
random_shuffe( Deck.begin(), Deck.end(), ptr_fun( my_random ) );
And if you're thinking about using rand(), you can just as well use the two-argument version of random_shuffle(), as using rand() is the default behaviour.
Posted: Mon Sep 17, 2007 7:46 am
by Zacariaz
no, i do not know what a functor is, but now atleast i know it is important, though i dont know what difference its gonna make.
Well, i dont think im gonna need more from you, im dropping the functor stuff. think its more than i can comprihend right now.
But once again thank you for all your help!
Edit:
Now i only need to know how well the random_shuffle() works, so i know how many times to "shuffle" the cards
Posted: Mon Sep 17, 2007 7:54 am
by Solar
Zacariaz wrote:no, i do not know what a functor is, but now atleast i know it is important, though i dont know what difference its gonna make.
You know function pointers? In the C standard library, there is a function qsort() which can be used to sort an array. One of the parameters to qsort() is a pointer to a function that does the comparison between two objects, so you can use qsort() on any type of data structure, even user-defined ones, as long as you have a compare function for them.
A functor, basically, is the same concept taken into C++: A class that has operator() overloaded, so you could, given an instance X of that class, execute X().
And because sometimes you don't
have a class for which you could readily overload operator(), there is ptr_fun(), which takes a function pointer as argument, and returns a functor.
The C++ header <algorithm> contains many useful, well, algorithms, and if you know how to implement a functor, you can do pretty amazing stuff with only a few lines of code.
Bottom line of all this techno-blurb is, once you dropped the idea of doing a linked list yourself, and switched to using <vector>, you can use all the nice stuff in <algorithms> with relative ease.
Posted: Thu Sep 20, 2007 1:42 pm
by eboyd
nevermind.