Нарезка объектов: доступ к методам производного класса из объекта базового класса.

Изменить :

  1. Проблема заключается в файле GoFish.h, а точнее в конструкторе, где он пытается создать экземпляр объекта player.

  2. Компилятор выдает следующее сообщение об ошибке: Нет члена с именем «noOfBooks» в «Player».

GoFish() {players = new GoFishPlayer[2];} // Instantiate two players

Нарезка объектов кажется одной из самых неоднозначных концепций ООП для начинающих. Я работал над этой карточной игрой на C++, где у меня есть базовый класс с именем Player и производный класс с именем GoFishPlayer. При попытке получить доступ к методам объекта GoFishPlayer, на который ссылается объект Player, программа имеет тенденцию отсекать определенные методы и атрибуты для производного класса, тем самым делая его клоном базового объекта. Есть ли способ преодолеть эту проблему?

Игра.ч

Абстрактный класс Game : формирует основу для обеих игр — GoFish и CrazyEights.

class Game {

protected:
Deck* deck;
Player* players;
int player_id;

public:
Game(){
    deck = Deck::get_DeckInstance(); // Get Singleton instance
    player_id = choosePlayer();
    players = NULL;
}
....
}

GoFish.h

Производный класс GoFish. Проблема заключается в конструкторе, когда я пытаюсь создать экземпляр объекта Player, полученного из класса Game.

class GoFish : public Game{

static GoFish* goFish;
GoFish() {players = new GoFishPlayer[2];} // Instantiate two players

public:
static GoFish* get_GoFishInstance() {
    if(goFish == NULL)
        goFish = new GoFish();

    return goFish;
}

Игрок.ч

class Player{

protected:
std::string playerName;
Hand hand;
bool win;

public:
Player(){ 
    playerName = "Computer"; // Sets default AI name to Computer
    hand = Hand(); // Instatiate the hand object
    win = false;
}
....

GoFishPlayer.h

class GoFishPlayer : public Player {

private:
std::vector <int> books;
int no_of_books;

public:
GoFishPlayer() {
    no_of_books = 0;
    books.resize(13);
}

int noOfBooks(){return no_of_books;}
void booksScored() {no_of_books++;}

bool checkHand() {}
....

person Luv    schedule 28.03.2016    source источник
comment
Это много кода — на что мы на самом деле должны смотреть?   -  person Oliver Charlesworth    schedule 28.03.2016
comment
где ваш код, который вызывает нарезку объектов?   -  person Guillaume Racicot    schedule 28.03.2016
comment
Это указатели - там нет нарезки.   -  person Oliver Charlesworth    schedule 28.03.2016
comment
Компилятор выдает следующую ошибку: нет элемента с именем «noOfBooks» в «Player», кажется, что он не может найти следующую функцию.   -  person Luv    schedule 28.03.2016
comment
Хорошо, это не проблема нарезки, просто так работает полиморфизм.   -  person Oliver Charlesworth    schedule 28.03.2016
comment
Ok. Как-нибудь обойти это?   -  person Luv    schedule 28.03.2016


Ответы (1)


Формулировка вашего вопроса кажется мне двусмысленной, но, насколько я понимаю, вы пытаетесь получить доступ к методам GoFishPlayer через ссылку на объект Player? Это не проблема, вызванная нарезкой объектов, это просто то, как работает полиморфизм.

Вам нужно преобразовать ссылку на объект Player, чтобы она стала ссылкой на объект GoFishPlayer.

class Parent
{
    public:
        void foo() { std::cout << "I'm a parent" << std::endl; }
};

class Derived : public Parent
{
    public:
        void bar() { std::cout << "I'm a derived" << std::endl; }
};


int main()
{
    Derived d;

    // reference to a derived class stored as a prent reference
    // you can't access derived methods through this
    Parent& p_ref = d;
    // this won't work
    // p_ref.bar();

    Derived& d_ref = static_cast<Derived&>(p_ref);
    // this works
    d_ref.bar();
}

Это работает только в том случае, если вы точно знаете, что p_ref на самом деле относится к типу Derived или к типу, который наследуется от Derived. Если вы не можете быть уверены, вам нужно выполнить проверку во время выполнения, используя dynamic_cast, а затем перехватить любые std::bad_cast исключения, которые выдаются.

person Fibbs    schedule 28.03.2016
comment
Но в целом этого делать не следует. (т. е. хранить указатели на базу — это плохой дизайн, если вам действительно нужен доступ к производным членам.) - person Oliver Charlesworth; 28.03.2016
comment
Иногда это неизбежно, хотя в таких ситуациях я бы предпочел, чтобы база реализовывала полный интерфейс с виртуальными методами, чтобы не было необходимости в dynamic_cast. - person Fibbs; 28.03.2016