Fixing C++ Card Class Errors in Visual C++ 6

  • Context: Comp Sci 
  • Thread starter Thread starter Math Is Hard
  • Start date Start date
  • Tags Tags
    C++ Class Errors
Click For Summary

Discussion Overview

The discussion revolves around issues encountered while implementing a C++ class for playing cards, specifically focusing on syntax errors in Visual C++ 6, the use of enums, and operator overloading for output. Participants are sharing code snippets, troubleshooting errors, and clarifying concepts related to C++ programming.

Discussion Character

  • Technical explanation
  • Debate/contested
  • Homework-related

Main Points Raised

  • One participant describes encountering multiple syntax errors in their implementation of a Card class, particularly related to the return type of member functions.
  • Another participant suggests that the return type should be fully qualified as Card::Rank instead of just Rank.
  • There is a discussion about how enums can be constructed from integers, with some participants clarifying that this is a feature of C++ enums.
  • A participant expresses confusion about how the friend function for outputting a Card works and how it accesses private member functions.
  • Another participant points out that the friend function must be defined within the correct namespace to access private members of the Card class.
  • One participant seeks advice on how to implement operator overloading for outputting an array of Card objects in a Deck class.

Areas of Agreement / Disagreement

Participants generally agree on the need for fully qualifying enum types and the mechanics of operator overloading. However, there are varying levels of understanding regarding the implementation details, particularly with respect to accessing private members and constructing enums from integers.

Contextual Notes

Some participants express frustration with compiler error messages, indicating that they may not be clear or helpful in diagnosing issues. There is also mention of differences in how various compilers handle similar code, suggesting that behavior may vary across environments.

Who May Find This Useful

This discussion may be useful for students or programmers working on C++ assignments involving class implementation, operator overloading, and enum usage, particularly in the context of card games or similar applications.

Math Is Hard
Staff Emeritus
Science Advisor
Gold Member
Messages
4,663
Reaction score
36
Hi. I am working on an assignment writing the implementation for a class of playing cards.
http://www.pic.ucla.edu/~nathan/cgi-bin/moin.cgi/la1#head-111d7fc9df65f327018fa94234ab0b23c0857e98
Here is the header file that we were provided.
Code:
//filename card.h
#ifndef CARD_H
#define CARD_H
#include <iostream>

namespace pic10b{
        class Card{
                friend std::ostream& operator<<(std::ostream& os, const Card& c);
        public:
                enum Rank {TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE};
                enum Suit {CLUB, DIAMOND, HEART, SPADE};
                Card(){rank = TWO; suit = CLUB;};
                Card( Rank r, Suit s);
                Card( const Card& c );
                Rank getRank() const;
                Suit getSuit() const;
                bool isFaceCard() const;
                std::string toString() const;
                bool operator<(const Card& c) const;
                bool operator>(const Card& c) const;
                bool operator<=(const Card& c) const;
                bool operator>=(const Card& c) const;
                bool operator==(const Card& c) const;
                bool operator!=(const Card& c) const;
        private:
                std::string abbr() const;
                Rank rank;      
                Suit suit;
        };

}
#endif
I have written two constructors and the getRank() and getSuit() member functions so far.
Code:
//filename card.cpp
#include "card.h"
using namespace pic10b;
using namespace std;

Card::Card(Rank r, Suit s)
{
	rank = r;
	suit = s;
}
                

Card::Card(const Card& c )
{
	rank = c.getRank();
	suit = c.getSuit();
}

           
Rank Card::getRank() const  //errors reference this line
{
	return rank;
}
             
Suit Card::getSuit() const
{
	return suit;
}
I am working in Visual C++ 6 and getting some errors:
error C2143: syntax error : missing ';' before 'tag::id'
error C2501: 'Rank' : missing storage-class or type specifiers
fatal error C1004: unexpected end of file found

and all reference the
Rank Card::getRank() const
line in my card.cpp file.
Am I missing something obvious? Thanks!
 
Last edited by a moderator:
Physics news on Phys.org
I also have a simple driver that I'm using:
Code:
#include<iostream>
#include "card.h"
#include<string>
#include<cstdlib>

using namespace pic10b;
using namespace std;

int main()
{        
        return 0;
}
just a stripped down version of my prof's to provide a main() function.
 
Last edited:
The problem is that the full name of that type is Card::Rank.

In the declaration Rank Card::getRank() const, you are not yet within the scope of Card when you are declaring the return type... so you have to fully qualify it as Card::Rank.


Actually, I fibbed slightly. The full name is pic10b::Card::Rank. But I guess that using directive means that you don't have to specify the pic10b:: there.


Oh, and as a plug for gcc, it figured out that you were trying to name a type (MSVC++ thought you were trying to declare a variable named Rank) and it emits the error:

error: `Rank' does not name a type
 
Last edited:
OMG! You RULE, Hurkyl! Thank you!
 
FWIW Borland C++ (an ancient version) let's this through with a warning:

Warning card.cpp 20: Use qualified name to access member type 'pic10b::Card::Rank'
Warning card.cpp 25: Use qualified name to access member type 'pic10b::Card::Suit'

Line 20 was your
Rank Card::getRank() const //errors reference this line

But we already knew CPP compilers are not written so that mortals can understand the error messages. Tell me something new... :rolleyes:
 
Thanks. I'm sure y'all haven't seen the last of me. I'll be back after I get into more trouble!
 
There's something that is confusing me. In my teacher's driver he makes a new card like so:
Code:
                int r = rand()%13;
                int s = rand()%4;
                cout << "Round " << i+1 <<": Drawing first random card...";
                Card::Suit S = Card::Suit(s);
                Card::Rank R = Card::Rank(r);
                Card c1(R, S);
                cout << "it's a " << c1.toString() << endl;

I don't really understand how Suit(s) works in
Card::Suit S = Card::Suit(s);
since Suit is a member variable and not a function. The parentheses confuse me.
I'm not clear on how it takes an int value and casts it as a Suit enum type. Is this just something you can do with enums?
Same question for Rank(r) of course.
 
Card::Suit isn't a variable, it's a type... and you're invoking one of its constructors.


Try out this piece of code:

std::count << char(65) << std::endl;
 
OK, thanks. I guess I just haven't seen anything like that before.
 
  • #10
One last thing I am stuck on. He has this private member function that returns a string that is an abbreviation of the card.
If card c1 is a King of Clubs, the programmer can just do
cout << c1;
in main() and it will print "KC"
In the header, the function declaration looks like this:
Code:
private:
                std::string abbr() const;
I can't figure out how cout<< would know what to do, or how to implement this. Any hints?

I don't have any friends, so I figure it has to be one the member functions that calls it, but I don't know which one.
 
  • #11
Math Is Hard said:
I don't have any friends
Such is the life of a computer programmer. :cry:

Er, actually you do:

friend std::ostream& operator<<(std::ostream& os, const Card& c);

So if you write that function, it will be able to access the abbr() method.
 
  • #12
Hurkyl said:
Such is the life of a computer programmer. :cry:

Er, actually you do:

friend std::ostream& operator<<(std::ostream& os, const Card& c);

So if you write that function, it will be able to access the abbr() method.

:smile: :smile: :smile:
ayeee! I missed that. My eyeballs have gone south!
 
  • #13
rats! I still can't beat this thing into submission.
I wrote the friend function my implementation file like so:
Code:
std::ostream& operator<<(std::ostream& os, const Card& c)
{
	os<<c.abbr();
	return os;
}
and then wrote the abbr() private member function like this, just to test:
Code:
std::string Card::abbr() const
{
	string str = "KC";
	return str;
}
but I'm getting an error "error C2248: 'abbr' : cannot access private member declared in class 'pic10b::Card'"
 
  • #14
I have a guess, haven't tested it yet, though.


Your class specified ::pic10b::operator<< as its friend, but you wrote ::operator<<. You need to write that function in the pic10b namespace, not the global namespace.
 
  • #15
That was it! Thanks so much!:smile:
 
  • #16
For the next assignment, we are writing a Deck class which uses the Card class we created. I wrote the default constructor, but I am stuck on overloading the << to cout a deck, which is an array of 52 cards.
The assignment is here:
http://www.pic.ucla.edu/~nathan/cgi-bin/moin.cgi/sa5
I figure for every position in the array I need to get the card that's there to return it's string abbreviation. I think I need to loop and grab strings and concatenate into one long string to finally put into os (I think!) but I can't figure out how to do this.

When we overloaded the "<<" just to cout<< a single card I used this:
Code:
std::ostream& operator<<(std::ostream& os, const Card& c)
{
	os<<c.abbr();
	return os;
}
which called this:
Code:
std::string Card::abbr() const
{
 //this just returned a 2-letter string for 
//the card abbreviation based on 
//the enums for the rank and suit.
}
so I can't figure out how to get each abbreviation from the cards in the deck. Any thoughts? Thanks. All I have now is a modified version of the card << overloader for a test.

I'll put what I have below in the next post.
 
Last edited by a moderator:
  • #17
The Deck header:
Code:
#ifndef DECK_H
#define DECK_H
#include <iostream>
#include "card.h"
namespace pic10b{
        class Deck{
  public:
   Deck(); // constructor   
  friend std::ostream& operator<<(std::ostream& os, const Deck& d);
  private:
   Card deck[52];
  };
}
#endif

The deck.cpp
Code:
#include "card.h"
#include "deck.h"
#include <sstream>
#include <string>
using namespace pic10b;
using namespace std;

namespace pic10b{
Deck::Deck() // constructor
{  	 	
int i = 0;

	for(Card::Suit s = Card::CLUB; s < Card::SPADE; s++)
	{
		for(Card::Rank r = Card::TWO; r < Card::ACE; r++)
		{
		Card c(r,s);
		deck[i] = c;
		i++;
		}
	}

}


std::ostream& operator<<(std::ostream& os, const Deck& d)
 {	
	 os<<"Test";
	 return os;
 }
}
 
  • #18
I think I need to loop and grab strings and concatenate into one long string to finally put into os (I think!) but I can't figure out how to do this.
How about starting with an empty string and writing a loop where you grab strings and append them to your string, and then put it in os? :-p I don't know what part with which you're having trouble.

Incidentally, you can write to a stream as many times as you like; there's no need to do it with a single insertion.
 
  • #19
Hi Hurkyl, Sorry for not being more specific. What I can't figure out is how to return a string value out of a card that's in the deck. I can reference d[0] for the first card in the deck, but I am not sure what to do from there.
 
  • #20
IF your card value and card suit are members of the class...it should be easy...just return a string or a char[2] or a char*...note a returning variables does not always have ot e on the left side it could be in your parameter list.

...if they are not inputed you will require to pas sthe suit and value.
 
  • #21
Well, the expression deck[0] is of type Card, right?

(technically, it's of type Card const&, but that's a minor quibble)

Oooh, I understand your problem now. You want to call abbr, but it's inaccessible, meaning you can't accomplish your goal of building one gigantic string.

(technically, you can, in a very roundabout fashion. But let's ignore that too)

So, that just means you'll have to find some way to output cards without calling abbr.
























If only there already existed a function for outputting a card... :rolleyes:
 
  • #22
well, let's see.. the Card class has an overloaded << friend which grabs the abbreviation string from the private member function abbr(), but I have absolutely no idea how to use the << in any other way than count<< in main(). Instead of printing it with count<< how can I give it to the os that is returned in my Deck << operator?
 
  • #23
nebbermind. It was easier than I thought.
os<<d.deck[0];
 
  • #24
Yep! :smile:
 
  • #25
*sigh* I'm having trouble getting the deck shuffling function going. I tried making it a friend function.
Code:
//deck.h header
friend void shuffle(const Deck& d);
for the implementation I just tried to replace a card with another to test.
Code:
//in deck.cpp
void shuffle(const Deck& d)
{
	d.deck[1] = d.deck[51];
}
and then I tried making a new card and putting it in the deck
Code:
//in deck.cpp
void shuffle(const Deck& d)
{
	Card::Suit s = Card::CLUB;
	Card::Rank r = Card::TWO;
	Card c(r,s);
	d.deck[1]=c;
}
but for both I get error C2678: binary '=' : no operator defined which takes a left-hand operand of type 'const class pic10b::Card' (or there is no acceptable conversion)

Do I need to overload the = operator in my Card class? Or my Deck class? Both? I'm getting confused because in my Deck constructor I can use =.
Code:
Deck::Deck() // constructor
{  	 	
int i = 0;

for(Card::Suit s = Card::CLUB; s <= Card::SPADE; s++){
	for(Card::Rank r = Card::TWO; r <= Card::ACE; r++)  {
		Card c(r,s);
		deck[i] = c;
		i++;
	  }
     }
}
Thanks. I am tearing my hair out over this %@!#! assignment.:frown:
 
  • #26
The compiler automatically supplies your class with a default implementation of operator=.


Now, the compiler message gives you a big hint -- what sort of arguments would you expect operator= to take here? Is there anything suspicious about the types you actually passed to operator=?
 
  • #27
I'm expecting it to take a card, which it does in the constructor. Why won't it take it in the shuffle function, if the card is an element of the deck?
 
  • #28
Right, you want to assign to a Card object.

But you are assigning to a const Card object. Did you really mean to assign to a Card constant?
 
  • #29
oops!:redface:
 

Similar threads

  • · Replies 2 ·
Replies
2
Views
5K
  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 1 ·
Replies
1
Views
1K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 8 ·
Replies
8
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 3 ·
Replies
3
Views
3K
  • · Replies 3 ·
Replies
3
Views
2K
Replies
9
Views
2K