【问题标题】:Object Slicing : Access dervied class methods from base class object对象切片:从基类对象访问派生类方法
【发布时间】:2016-03-28 16:33:57
【问题描述】:

编辑

  1. 问题出在 GoFish.h 文件中,在 constructor 中 具体来说,它试图实例化玩家对象。

  2. 编译器抛出以下错误消息:'Player'中没有名为'noOfBooks'的成员

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

对象切片对于初学者来说似乎是 OOP 中最模糊的概念之一。我一直在用 C++ 开发这款纸牌游戏,其中我有一个名为 Player 的基类和一个名为 GoFishPlayer 的派生类。当尝试访问引用回 Player 对象的 GoFishPlayer 对象的方法时,程序倾向于切掉派生类的特定方法和属性,从而使其成为基对象的克隆。有什么办法可以解决这个问题吗?

游戏.h

抽象类游戏:构成这两款游戏的基础 - 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

Derived Class GoFish - 当我尝试实例化从 Game Class 派生的 Player 对象时,问题出现在构造函数中

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;
}

播放器.h

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() {}
....

【问题讨论】:

  • 这么多代码——我们到底应该看什么?
  • 导致对象切片的代码在哪里?
  • 那些是指针 - 没有切片。
  • 编译器抛出以下错误-“'Player'中没有名为'noOfBooks'的成员”,似乎找不到以下函数
  • 好的 - 这不是切片问题,多态性就是这样工作的。

标签: c++ oop inheritance object-slicing


【解决方案1】:

您问题的措辞对我来说似乎模棱两可,但据我所知,您正试图通过引用 Player 对象来访问 GoFishPlayer 的方法?这不是对象切片造成的问题,而是多态性的工作原理。

您需要转换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 异常。

【讨论】:

  • 但一般来说,不应该这样做。 (即,如果您确实需要访问派生成员,那么存储指向基址的指针是不好的设计。)
  • 有时这是不可避免的,但在这种情况下,我更希望基础实现带有虚拟方法的完整接口,这样就不需要 dynamic_cast。
猜你喜欢
  • 2015-05-23
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 2015-11-07
  • 1970-01-01
相关资源
最近更新 更多