【问题标题】:Trying to make derived class, compiler expects default constructor for abstract base试图创建派生类,编译器期望抽象基的默认构造函数
【发布时间】:2013-11-17 05:29:24
【问题描述】:

我们正在尝试创建一个抽象类“Game”和派生类“FiveCardDraw”。 FiveCardDraw 的构造函数期望 Game 有一个默认构造函数,但我们的 Game 类不能有默认构造函数,因为我们有纯虚方法。解决办法是什么?

我们的错误看起来像 c:\users\wesley\documents\visual studio 2010\projects\lab4\lab4\fivecarddraw.cpp(14):error C2512: '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

游戏.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;
}

【问题讨论】:

    标签: c++ abstract pure-virtual


    【解决方案1】:

    除非你声明自己的构造函数,否则编译器会给你一个空的默认构造函数。你做了什么。

    如果不先创建所有子对象(包括基类的一个),就无法创建派生类。为此需要一个构造函数。

    protected:
        Game() {}
    

    注意,如果你想禁用复制,你还是应该使用正常的签名。

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

    在 C++11 中,您可以更明确地告诉编译器您要防止复制:

        Game(const Game&) = delete;
    

    同样对于默认构造函数,你可以告诉编译器你确实希望它自动生成一个:

        Game() = default;
    

    【讨论】:

    • 我尝试在我的基类 Game 中定义一个默认构造函数;但是我收到链接器错误,例如: 1>FiveCardDraw.obj : error LNK2019: unresolved external symbol "public: __thiscall Game::Game(void)" (??0Game@@QAE@XZ) 在函数“public: __thiscall FiveCardDraw”中引用::FiveCardDraw(void)" (??0FiveCardDraw@@QAE@XZ)
    • @user3000959:请注意,我提供了一个定义。空括号 {}=default,取决于 C++ 版本。但是链接器错误是好的。他们的意思是你让编译器开心。
    • @user3000959:是的。我的回答是Game() {},你把它改成了Game();那个改变会导致错误。
    • 我使用了 Game(){} 仍然得到 Game.obj : error LNK2001: unresolved external symbol "protected: static class Game * Game::game" (?game@Game@@1PAV1@A )
    • @user3000959:嗯,这是一个不同的错误,尽管可以用同样的方式解释。同样,您有一个没有定义的声明。在您的 .cpp 文件中写入 Game* Game::game = 0; 以解决该错误。
    【解决方案2】:

    FiveCardDraw 的构造函数期望 Game 有一个默认构造函数,但我们的 Game 类不能有默认构造函数,因为我们有纯虚方法。解决办法是什么?

    拥有抽象类并不意味着您不能定义或使用构造函数,它只是意味着创建该类型对象的唯一方法是作为基类子对象。

    所以继续为Game::Game() 定义一个合适的构造函数,然后从FiveCardDraw 的mem-initializer-list 中使用它。也许就这么简单

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

    或者您可能需要一些参数来初始化Deck 成员......

    顺便说一句,size_t 是一个糟糕的成员名称,因为 std::size_t 是一种类型。

    【讨论】:

    • 我同意所有这些......但值得注意的是,默认初始化的子对象不必在初始化列表中命名。除非你想初始化值。
    • 没错,但我通常更喜欢命名它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多