Blackjack 2.0 error overloading operator.

Back with the start to Blackjack 2.0. This code is supposed to create two classes, a "Card" class and a "Shoe" class and overload the operator<< to cout a Card.

I'm getting some sort of linking error.
"Error 1 error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Card const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABVCard@@@Z) referenced in function "public: void __thiscall Shoe::displayShoe(void)" (?displayShoe@Shoe@@QAEXXZ) C:\Users\ShawnDesk\documents\visual studio 2013\Projects\BlackJack2.0\BlackJack2.0\Blackjacl0200.obj BlackJack2.0"

"Error 2 error LNK1120: 1 unresolved externals C:\Users\ShawnDesk\documents\visual studio 2013\Projects\BlackJack2.0\Debug\BlackJack2.0.exe BlackJack2.0"



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>

using namespace std;

enum ranks { ACE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
	TEN, JACK, QUEEN, KING };
enum suit{ CLUBS, DIAMONDS, HEARTS, SPADES };

class Card{

public:

	
	friend ostream& operator<<(ostream& os, const Card& aCard);

	

	int m_value;
	int m_Rank;
	char m_Suit;
	char m_name;

};



class Shoe{

public:
	vector<Card>m_Shoe;

	Shoe(int numdecks = 6);
	~Shoe();
	void fillShoe();
	void shauffleShoe();
	void displayShoe();

};



Shoe::Shoe(int numdecks){
	m_Shoe.reserve(numdecks * 52);
}
Shoe::~Shoe(){

	m_Shoe.clear();

}
void Shoe::fillShoe(){

	char name[] = { 'A', '2', '3', '4', '5', '6', '7',
		'8', '9', 'T', 'J', 'Q', 'K' };
	char suit[] = { 'C', 'D', 'H', 'S' };

	vector<Card>::iterator iter = m_Shoe.begin();
	while (iter != m_Shoe.end()){
		for (int s = CLUBS; s <= SPADES; s++)
			for (int r = ACE; r <= KING; r++, iter++){
				iter->m_Rank = static_cast<ranks>(r);
				iter->m_Suit = suit[s];
				iter->m_value = r > 10 ? 10 : r;
				iter->m_name = name[r];

			}
	}
}

void Shoe::displayShoe(){
	for (int i = 0; i < 52; i++){
		for (vector<Card>::iterator iter = m_Shoe.begin();
			iter != m_Shoe.end(); iter++,i++){
			cout << *iter << " ";
		}
		cout << "\n";
	}

}
ostream& operator<<(ostream& os, Card& aCard){

	os << aCard.m_name << aCard.m_Suit;
	return os;
}

int main(){
	Shoe myshoe;
	myshoe.fillShoe();
	myshoe.displayShoe();
	return 0;


}
Compare line 18 and line 83. What's different besides the friend declaration?
const :) Thanks
It compiles now and I think the operator<< is properly overloaded, but I seem to couting empty chars. I need to see why.
A few problems.
Line 47: reserve() changes vector's capacity, but it does not affect its size (actual number of entries) or iterators. m_shoe is empty at this point.

Line 61: Since m_shoe is empty, this loop does not execute.

Line 67: r causes an out of bounds reference, siince r goes from 1-13, but names goes from 0-12.

Line 74: You're displaying the first 52 entries of an empty vector.

Suggestions:

Lines 22-25, 34: These should be private

Lines 23-24: Change these to use your enums.

Lines 56-58: You only need these translates when you display the card.

Provide a constructor for Card. You're actually constructing card at lines 64-67.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Card::Card (suit s, ranks r)
{   m_rank = r;
    m_suit = s;
    m_value = r > 10 ? 10 : r;
}	

Shoe::Shoe (int numdecks)
{   m_decks = 6;  //  We'll need this later
    m_shoe.reserve (numdecks * 52);
}

void Shoe::fillShoe()
{   for (int i = 0; i<m_decks; i++)
    {   for (int s = CLUBS; s <= SPADES; s++)
            for (int r = ACE; r <= KING; r++)
            {   m_shoe.push_back (Card((Suit)s,(Rank)r));
            }
    }
}

void Shoe::displayShoe()
{   for (size_t i = 0; i < m_shoe.size(); i++)
        cout << m_shoe[i] << "\n";
}

ostream& operator << (ostream& os, const Card & aCard)
{   static char name[] = { 'A', '2', '3', '4', '5', '6', '7',
		'8', '9', 'T', 'J', 'Q', 'K' };
    static char suit[] = { 'C', 'D', 'H', 'S' };

    os << name[aCard.m_rank-1] << suit[aCard.m_suit];
    return os;
}
Last edited on
I found the problem with reserve. I changed it to resize. While working on that bug I found this strange behavior:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Name{

public: 
	int  m_age;
	string m_fn;
	string m_ln;

};

class Group{
public:
	Group(int num = 3);
	vector<Name>m_group;


};

Group::Group(int num){
//	m_group.reserve(num);  //This did not work
	m_group.resize(num);
}
int main(){
	Group buddies;

//Why can't I do this?
//for (int i = 0, vector<Name>::iterator iter = buddies.m_group.begin();
//	iter != buddies.m_group.end(); iter++, i++)
//		cout << i << '\n';
//trying to declare i , iter blows up

//for (int i = 0, char x = 'C'; i < 10; i++) but this is perfectly fine
	
	int i = 0;
	for (vector<Name>::iterator iter = buddies.m_group.begin();
		iter != buddies.m_group.end(); iter++, i++)
		cout << i << '\n';
	


}


Why cant I declare i and iter in the same for statement with the comma separator?
Last edited on
I reworked the code. I'm having a little trouble iterating through enums. I have it working but it looks a little convoluted.

Also, I should I worry about destructors or does the vector handle releasing the memory?

so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>

using namespace std;

enum c_rank{ACE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
	TEN, JACK, QUEEN, KING, ENDRANK};
enum suit{ CLUBS, DIAMONDS, HEARTS, SPADES, ENDSUIT }; // there's got be a better way to iterate
                                                   // through these enums

c_rank operator++(c_rank& r, int){     // allow iteration through c_rank enums
	int i;
	if (r == ENDRANK)
		return r;
	i = r;
	i++;
	return r = static_cast<c_rank>(i);
}
suit operator++(suit& s, int){     // allow iteration through suit enums
	int i;
	if (s == ENDSUIT)
		return s;
	i = s;
	i++;
	return s = static_cast<suit>(i);
}
class Card{
	int m_value;
	c_rank m_Rank;   // I had to use c_rank instead of rank
	// If I used rank, it would show as "ambiguous"
	// down here.
	suit m_Suit;
	//char m_name; // This isn't needed

public:

	Card(c_rank r, suit s);
	friend ostream& operator<<(ostream& os, const Card& aCard);



	

};
Card::Card(c_rank r, suit s) : m_Rank(r), m_Suit(s){

	m_value = static_cast<int>(r);
	m_value = m_value > 9 ? 10 : m_value;
}



class Shoe{

public:
	vector<Card>m_Shoe;

	Shoe(int numdecks = 6);
	void shauffleShoe();
	void displayShoe();

};


Shoe::Shoe( int numdecks){

	for (int i = 0; i < numdecks;i++)
		for (c_rank r = ACE; r < ENDRANK; r++)
			for (suit s = CLUBS; s <ENDSUIT; s++){
				Card curcard(r, s);
				m_Shoe.push_back(curcard);
			}

}

void Shoe::displayShoe(){
	int i = 0;
	for (vector<Card>::iterator iter = m_Shoe.begin();
		iter != m_Shoe.end(); iter++){
		cout << *iter << " ";
		if (i++ == 25){
			cout << '\n';
			i = 0;

		}
	}
	
}
void Shoe::shauffleShoe(){

	random_shuffle(m_Shoe.begin(), m_Shoe.end());

}
ostream& operator<<(ostream& os, const Card& aCard){

	char name[] = { 'X', 'A', '2', '3', '4', '5', '6', '7', '8',
		'9', 'T', 'J', 'Q', 'K' };  // quick and dirty avoid indice math
	char suit[] = { 'C', 'D', 'H', 'S' };

	os << name[aCard.m_Rank]<< suit[aCard.m_Suit];
	return os;
}

int main(){
	Shoe myshoe;
	myshoe.displayShoe();
	myshoe.shauffleShoe();
	cout << '\n';
	myshoe.displayShoe();

	return 0;


}
So far - I started splitting it up:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//Card.h

#ifndef CARDS_H
#define CARDS_H

#include <iostream>
#include <vector>

using std::ostream;
using std::vector;

enum c_rank{
	ACE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
	TEN, JACK, QUEEN, KING, ENDRANK
};
enum suit{ CLUBS, DIAMONDS, HEARTS, SPADES, ENDSUIT }; // there's got be a better way to iterate
// through these enums


class Card{
	int m_value;
	c_rank m_Rank;  
	suit m_Suit;
	
public:

	Card(c_rank r, suit s);
	friend ostream& operator<<(ostream& os, const Card& aCard);

};
class Hand{

public:
	vector<Card>m_Hand;
	int m_Aces = 0;
	bool m_IsDealer;
	void displayHand();

};
class Shoe{

public:
	vector<Card>m_Shoe;
	vector<Card>::iterator m_curcard;

	Shoe(int numdecks = 6);
	void shauffleShoe();
	void displayShoe();
	void dealcard(Hand& hand);

};

#endif // !CARDS_H 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//Cards.cpp
#include <iostream>
#include <algorithm>
#include <vector>
#include "Cards.h"

using std::ostream;
using std::cout;


c_rank operator++(c_rank& r, int){     // allow iteration through c_rank enums
	int i;
	if (r == ENDRANK)
		return r;
	i = r;
	i++;
	return r = static_cast<c_rank>(i);
}
suit operator++(suit& s, int){     // allow iteration through suit enums
	int i;
	if (s == ENDSUIT)
		return s;
	i = s;
	i++;
	return s = static_cast<suit>(i);
}
ostream& operator<<(ostream& os, const Card& aCard){

	char name[] = { 'X', 'A', '2', '3', '4', '5', '6', '7', '8',
		'9', 'T', 'J', 'Q', 'K' };  // quick and dirty avoid indice math
	char suit[] = { 'C', 'D', 'H', 'S' };

	os << name[aCard.m_Rank] << suit[aCard.m_Suit];
	return os;
}
Card::Card(c_rank r, suit s) : m_Rank(r), m_Suit(s){//card constructor

	m_value = static_cast<int>(r);
	m_value = m_value > 9 ? 10 : m_value;
}
Shoe::Shoe(int numdecks){      //Shoe constructor

	for (int i = 0; i < numdecks; i++)
		for (c_rank r = ACE; r < ENDRANK; r++)
			for (suit s = CLUBS; s <ENDSUIT; s++){
				Card curcard(r, s);
				m_Shoe.push_back(curcard);
			}
	m_curcard = m_Shoe.begin();

}
void Shoe::displayShoe(){
	int i = 0;
	for (vector<Card>::iterator iter = m_Shoe.begin();
		iter != m_Shoe.end(); iter++){
		cout << *iter << " ";
		if (i++ == 25){
			cout << '\n';
			i = 0;

		}
	}

}
void Shoe::shauffleShoe(){

	random_shuffle(m_Shoe.begin(), m_Shoe.end());
	m_curcard = m_Shoe.begin();

}
void Shoe::dealcard(Hand& hand){
	hand.m_Hand.push_back(*m_curcard);
	m_curcard++;
}
void Hand::displayHand(){
	for (vector<Card>::iterator iter = m_Hand.begin();
		iter != m_Hand.end(); iter++)
		cout << *iter << " ";
	cout << '\n';
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Main.cpp

#include <iostream>
#include <ctime> 
//#include <cstdio>

#include "Cards.h"

using std::cout;

int main(){
	Shoe myshoe(4);
	Hand hand1, hand2;

	srand((unsigned)time(0));

	myshoe.displayShoe();
	myshoe.shauffleShoe();
	cout << '\n';
	myshoe.displayShoe();
	cout << '\n';

	myshoe.dealcard(hand1);
	myshoe.dealcard(hand2);
	myshoe.dealcard(hand1);
	myshoe.dealcard(hand2);
	hand1.displayHand();
	cout << '\n';
	hand2.displayHand();
	cout << '\n';

	return 0;
}
This is a rough look at the classes I'm thinking about to handle the flow of the game. A player should be able make hands dynamically for splitting pairs and resplitting. The table should be able to add and remove players.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef PLAYER_H
#define PLAYER_H

#include<iostream>
#include "Cards.h"

class Player{

public:
	double wallet;
	vector<Hand>m_Hands;//dynamic for splitting
	void addHands();

};

class Table{

public:
	vector<Player>m_Players; //dynamic for adding and removing
	void addPlayer();        //players
};
#endif // !PLAYER_H 
Topic archived. No new replies allowed.