user3000959
user3000959

Reputation: 13

Trying to make derived class, compiler expects default constructor for abstract base

We are trying to create an abstract class "Game" and derived class "FiveCardDraw." FiveCardDraw's constructor expects there to be a default constructor for Game, but our Game class can't have a default constructor because we have pure virtual methods. What is the solution?

Our error looks like c:\users\wesley\documents\visual studio 2010\projects\lab4\lab4\fivecarddraw.cpp(14):error C2512: 'Game' : no appropriate default constructor available

Game.h

#ifndef GAME_H
#define GAME_H
#include "stdafx.h"
#include <string>
#include <vector>
#include "Player.h"
#include "Deck.h"

struct Player;
class Deck;

class Game{
protected:
    Deck mainDeck;
    vector<Player*> players;
    static Game* game;
public:
    static Game* instance();
    static void start_game(const string&);
    static void stop_game();
    void addPlayer(const string&);
    Player* find_player(const string&);
    virtual ~Game();
    virtual int before_turn(Player&)=0;
    virtual int turn(Player&)=0;
    virtual int after_turn(Player&)=0;
    virtual int round()=0;
    virtual int before_round()=0;
    virtual int after_round()=0;
private:
    Game(Game&);
    void operator=(Game&);
};

#endif

Game.cpp

#include "stdafx.h"
#include <string>
#include <vector>
#include "Player.h"
#include "Deck.h"
#include "Game.h"
#include "FiveCardDraw.h"
using namespace std;

static const int INSTANCE_NOT_AVAILABLE_ERROR=12;
static const int GAME_ALREADY_STARTED_ERROR=13;
static const int UNKNOWN_GAME_ERROR=14;
static const int NO_GAME_IN_PROGRES_ERROR=15;
static const int ALREADY_PLAYING_ERROR=16;


Game* Game::instance(){
    if(game==0){
        throw INSTANCE_NOT_AVAILABLE_ERROR;
    }
    else{
        return game;
    }
}
void Game::start_game(const string& gameType){
    if(game!=0){
        throw GAME_ALREADY_STARTED_ERROR;
    }else if(gameType.find("FiveCardDraw")!=string::npos){
        game = new FiveCardDraw();  
    }
    else{  
        throw UNKNOWN_GAME_ERROR;
    }
}

void Game::stop_game(){
    if(game==0){
        throw NO_GAME_IN_PROGRES_ERROR;
    }
    else{
        delete game;
        game=0;
    }
}


void Game::addPlayer(const string& playerName){
    for(unsigned int i=0; i<players.size();++i){
        if(playerName==players[i]->Name){
            throw ALREADY_PLAYING_ERROR;
        }
    }
    players.push_back(new Player(playerName));
}

Player* Game::find_player(const string& playerName){
    for(unsigned int i=0; i<players.size();++i){
        if(playerName==players[i]->Name){
            return players[i];
        }
    }
    return 0;
}

Game::~Game(){
    for(unsigned int i=0; i<players.size();++i){
        delete players[i];
    }
}

FiveCardDraw.h

#ifndef FIVECARDDRAW_H
#define FIVECARDDRAW_H
#include "stdafx.h"
#include <string>
#include <vector>
#include "Player.h"
#include "Deck.h"
#include "Game.h"

class FiveCardDraw : public Game {

protected:
    unsigned int size_t;
    Deck discardDeck;
public:
    FiveCardDraw();
    virtual int before_turn(Player &);
    virtual int turn (Player &);
    virtual int after_turn (Player &);
    virtual int before_round();
    virtual int round();
    virtual int after_round();
};


#endif

FiveCardDraw.cpp

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include "FiveCardDraw.h"
#include "Card.h"

using namespace std;

static const int NUM_SUITS=4;
static const int NUM_RANKS=13;
static const int CARDS_PER_HAND =5;
static const int NOT_ENOUGH_CARDS_ERROR=16;

FiveCardDraw::FiveCardDraw() {
    size_t = 0;

    //nested for loop to generate all 52 possible cards
    for(unsigned int s=0; s<NUM_SUITS; ++s){
        for(unsigned int r=0; r<NUM_RANKS; ++r){
            mainDeck.addCard( Card(Card::rank_(r),Card::suit_(s)));
        }
    }
}
int FiveCardDraw::before_turn(Player & player){
    cout<<player.Name<<" has "<<player.myHand;
    cout<<endl;
    string toDiscard="";
    while(toDiscard!="none"){
        cout<<"Enter the number of a card you wish to discard (0-4) or \"none\" if you are done discarding."<<endl;
        cin>>toDiscard;
        if(toDiscard=="0" || toDiscard=="1" ||toDiscard=="2" || toDiscard=="3" || toDiscard=="4"){
            unsigned int intToDiscard=stoi(toDiscard);
            if(intToDiscard<toDiscard.size()){
                discardDeck.addCard(player.myHand[intToDiscard]);
                player.myHand.remove_card(intToDiscard);
            }
            else{
                cout<<"There is no longer a card at position "<<intToDiscard<<"."<<endl;
            }
        }
    }
    return 0;
}
int FiveCardDraw::turn (Player & player){
    unsigned int numCardsToReplace=CARDS_PER_HAND-player.myHand.size();
    if(mainDeck.size()+discardDeck.size()<numCardsToReplace){
        return NOT_ENOUGH_CARDS_ERROR;
    }
    if(mainDeck.size()<numCardsToReplace){
        discardDeck.shuffle();
        for(unsigned int i=0; i<numCardsToReplace; ++i){
            mainDeck.addCard(discardDeck.removeCard());
        }
    }

    while(player.myHand.size()<CARDS_PER_HAND){
        player.myHand<<mainDeck;
    }
    return 0;
}

int FiveCardDraw::after_turn (Player & player){
    cout<<player.Name<<" now has "<<player.myHand;
    cout<<endl;
    return 0;
}

int FiveCardDraw::before_round(){
    return 0;
}
int FiveCardDraw::round(){
    return 0;
}
int FiveCardDraw::after_round(){
    return 0;
}

Upvotes: 1

Views: 587

Answers (2)

aschepler
aschepler

Reputation: 72356

FiveCardDraw's constructor expects there to be a default constructor for Game, but our Game class can't have a default constructor because we have pure virtual methods. What is the solution?

Having an abstract class doesn't mean you can't define or use a constructor, it just means the only way to create objects of that type is as a base class subobject.

So go ahead and define an appropriate constructor for Game::Game(), and then use it from the mem-initializer-list of FiveCardDraw. Maybe it's as simple as

Game::Game()
    : mainDeck(),
      players()
{}

FiveCardDraw::FiveCardDraw()
    : Game(),
      size_t(0),
      discardDeck()
{}

or maybe you need some arguments to initialize the Deck members....

By the way, size_t is a poor name for a member, since std::size_t is a type.

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283684

The compiler will give you an empty default constructor unless you declare constructors of your own. Which you did.

The derived class can't be created without first creating all subobjects, including one for the base class. A constructor is needed for that.

protected:
    Game() {}

Note, if you want to disable copying, you should still use the normal signature.

private:
    Game(const /* <- right there */ Game&);

In C++11, you can tell the compiler you want to prevent copies more explicitly:

    Game(const Game&) = delete;

And likewise for the default constructor, you can tell the compiler you do want it to automatically generate one after all:

    Game() = default;

Upvotes: 1

Related Questions