Reputation: 157
I am trying to implement a card game in c++ using VS-2013, and I have a "Player" class. The "Player" class is abstract in the sense that no actual objects of that class are to be initialized. Instead, it is only there to be inherited to 4 different player classes (with 4 different playing strategies) - "PlayerType1" to "PlayerType4".
This is my Player.h file:
#ifndef PLAYER_H_
#define PLAYER_H_
#include <iostream>
#include "Hand.h"
using namespace std;
class Player : public Hand {
private:
const string name;
protected:
Hand myHand;
public:
string getName(); //Returns the name of the player
virtual int getShapeToAsk() = 0;
virtual int getPlayerToAsk() = 0;
virtual ~Player();
};
class PlayerType1 : public Player { //For strategy 1
PlayerType1();
virtual int getShapeToAsk() override;
virtual int getPlayerToAsk() override;
~PlayerType1();
};
class PlayerType2 : public Player { //For strategy 2
PlayerType2();
virtual int getShapeToAsk() override;
virtual int getPlayerToAsk() override;
~PlayerType2();
};
class PlayerType3 : public Player { //For strategy 3
private:
int myNumber, numOfPlayers, nextPlayer;
public:
PlayerType3(int myNumber, int numOfPlayers);
virtual int getShapeToAsk() override;
virtual int getPlayerToAsk() override;
~PlayerType3();
};
class PlayerType4 : public Player { //For strategy 4
private:
int myNumber, numOfPlayers, nextPlayer;
public:
PlayerType4(int myNumber, int numOfPlayers);
virtual int getShapeToAsk() override;
virtual int getPlayerToAsk() override;
~PlayerType4();
};
#endif
And this is my Player.cpp file:
#include <iostream>
#include <vector>
#include "Hand.h"
#include "Player.h"
using namespace std;
//Player functions
string Player::getName(){
return (this->name + " " + this->toString());
}
Player::~Player(){}
//PlayerType1 functions
PlayerType1::PlayerType1(){}
int PlayerType1::getShapeToAsk(){
int maxCount = 0, maxValue, currValue, count;
for (std::vector<Card*>::reverse_iterator i = this->myHand.getCards().rbegin(); i != this->myHand.getCards().rend(); i++){
count = 1;
currValue = (**i).getValue();
for (i; (i != this->myHand.getCards().rend()) && ((**i).getValue() == currValue); ++i){
count++;
}
if (count > maxCount){
maxCount = count;
maxValue = currValue;
if (maxCount == 4) // no need to look at the rest of the hand
break;
}
}
return maxValue;
}
int PlayerType1::getPlayerToAsk(){ return -1; } //-1 means "I am a player of type 1 or 2". Game's responsibility to change later.
PlayerType1::~PlayerType1(){}
//PlayerType2 functions
PlayerType2::PlayerType2(){}
int PlayerType2::getShapeToAsk(){
int minCount = 5, minValue, currValue, count;
for (std::vector<Card*>::iterator i = this->myHand.getCards().begin(); i != this->myHand.getCards().end(); i++){
count = 1;
currValue = (**i).getValue();
for (i; (i != this->myHand.getCards().end()) && ((**i).getValue() == currValue); ++i){
count++;
}
if (count < minCount){
minCount = count;
minValue = currValue;
if (minCount == 1) // no need to look at the rest of the hand
break;
}
}
return minValue;
}
int PlayerType2::getPlayerToAsk(){ return -1; } //-1 means "I am a player of type 1 or 2". Game's responsibility to change later.
PlayerType2::~PlayerType2(){}
//PlayerType3 functions
PlayerType3::PlayerType3(int myNumber, int numOfPlayers){
this->myNumber = myNumber;
this->numOfPlayers = numOfPlayers;
if (myNumber == 1) this->nextPlayer = 2;
else this->nextPlayer = 1;
}
int PlayerType3::getShapeToAsk(){
int maxCount = 0, maxValue, currValue, count;
for (std::vector<Card*>::reverse_iterator i = this->myHand.getCards().rbegin(); i != this->myHand.getCards().rend(); i++){
count = 1;
currValue = (**i).getValue();
for (i; (i != this->myHand.getCards().rend()) && ((**i).getValue() == currValue); ++i){
count++;
}
if (count > maxCount){
maxCount = count;
maxValue = currValue;
if (maxCount == 4) // no need to look at the rest of the hand
break;
}
}
return maxValue;
}
int PlayerType3::getPlayerToAsk(){
int temp = this->nextPlayer;
this->nextPlayer++;
while ((this->nextPlayer == this->myNumber) || (this->nextPlayer > this->numOfPlayers)){
if (this->nextPlayer == this->myNumber) this->nextPlayer++;
if (this->nextPlayer > this->numOfPlayers) this->nextPlayer = 1;
}
return temp;
}
PlayerType3::~PlayerType3(){}
//PlayerType4 functions
PlayerType4::PlayerType4(int myNumber, int numOfPlayers){
this->myNumber = myNumber;
this->numOfPlayers = numOfPlayers;
if (myNumber == 1) this->nextPlayer = 2;
else this->nextPlayer = 1;
}
int PlayerType4::getShapeToAsk(){
int minCount = 5, minValue, currValue, count;
for (std::vector<Card*>::iterator i = this->myHand.getCards().begin(); i != this->myHand.getCards().end(); i++){
count = 1;
currValue = (**i).getValue();
for (i; (i != this->myHand.getCards().end()) && ((**i).getValue() == currValue); ++i){
count++;
}
if (count < minCount){
minCount = count;
minValue = currValue;
if (minCount == 1) // no need to look at the rest of the hand
break;
}
}
return minValue;
}
int PlayerType4::getPlayerToAsk(){
int temp = this->nextPlayer;
this->nextPlayer++;
while ((this->nextPlayer == this->myNumber) || (this->nextPlayer > this->numOfPlayers)){
if (this->nextPlayer == this->myNumber) this->nextPlayer++;
if (this->nextPlayer > this->numOfPlayers) this->nextPlayer = 1;
}
return temp;
}
PlayerType4::~PlayerType4(){}
I get the following errors:
Error error C2512: 'Player' : no appropriate default constructor available <PATH>\player.cpp
A total of 4 errors of that type, each pointing to the constructors of PlayerType1 to PlayerType4.
When I add an empty default constructor to my "Player" class, it solves the problem and I get a successful build. However, I fail to see why I need to define a default constructor for the "Player" class, as I never initialize an object of that class.
I should also mention I have another class in my project ("Card" class) that is abstract and is just there to be inherited by other classes ("FigureCard" and "NumericCard"), and also has no constructor, and the derived classes have their own constructors, and that causes no error. I fail to see the difference.
I searched other questions, but they all relate to cases in which a default constructor was not defined, and an initialization was attempted of that class elsewhere in the code. That is not my case since I am not initializing an object of class "Player", only the 4 derived classes.
Please help! Thank you in advance.
Upvotes: 0
Views: 2568
Reputation: 62045
Your Player
class has a private: const string name;
member. Look at your Card
class; I bet it does not have such a member. That's the difference.
The thing is, the const string name;
member must somehow be initialized, and since it is private
, it must be initialized within the Player
class. (Language rules prohibit the initialization of a private member of a class from a derived class.) Therefore, the Player
class must have a constructor which will initialize the name
member. The empty constructor achieves this.
Upvotes: 0
Reputation: 1103
Even if your Player class is abstract, you must define a constructor because your class has members. When you create an instance of a derived class (any of your PlayerType) class, it will call the constructor of the base class. This is how inheritence works...
In that case, make it protected (making it public would be useless anyway because it's a pure virtual class).
Upvotes: 1