0

I'm not sure how to call a derived class function from the base class without getting some sort of error, here's a skeleton of the code I'm trying to work with...

class DiceGame{
public:
    virtual void play(){
        // Trying to call the derived class
        // Knockout's play function in here
        // I've been trying this

        DiceGame *game = new Knockout;
        game->play();

        // But it gives me a memory error
    }

class Knockout : public DiceGame{
    void play(){
        // This has the stuff I want to call
    }

main(){
    DiceGame *game = new DiceGame();
    game->play();
}

I have tried forward declaration of the Knockout class, but that gives me an incomplete forward declaration error as well, any advice?

  • 8
    Generally speaking a BaseClass should not know about it's derived classes. – Borgleader Sep 12 '17 at 14:42
  • My suggestion would be to make `virtual void play_internal()` and derive that, and you would call that inside `play()` (which would no longer be virtual) – Borgleader Sep 12 '17 at 14:43
  • @Borgleader Not related to the question, but purely curiosity: in which case(s) should a BaseClass now about it's derived classes? – ivospijker Sep 12 '17 at 14:44
  • 4
    Sounds like you could use a [good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – NathanOliver Sep 12 '17 at 14:44
  • `DiceGame *game = new Knockout();` and get rid of DiceGame::play content. – KonstantinL Sep 12 '17 at 14:44
  • 1
    You are trying to call, from a virtual member function, the overridden implementation for that very same function on a new locally dynamically allocated instance specific derived type. This is all very suspicious to me and likely not the solution to your problem. – François Andrieux Sep 12 '17 at 14:46
  • @DrIvol I cant think of a case, but "never say never", hence "Generally speaking" – Borgleader Sep 12 '17 at 14:49
  • `main` returns `int`. Beware of using `new` where it isn't necessary. This is not Java or C#. In any case, if you really need dynamic allocation, you should consider using smart pointers instead of owning raw pointers. For example `auto game = std::make_unique();`. – François Andrieux Sep 12 '17 at 14:50
  • 1) You don't call the **overridden** function in the base class _directly_. 2) Your `main` function shouldn't be creating the (often abstract) base class; create the subclass of `DiceGame` that you want to play. (_Note type hierarchy means that `DiceGame *game = new SUBCLASS...` is valid_) 3) Then when you call `game->play()`, the subclass's implementation will be called automatically. – Disillusioned Sep 12 '17 at 14:50
  • @DrIvol @Borgleader Curiously recurring template pattern (CRTP) will access the derived members directly from the base, but then it knows exactly what the derived type is (you do like `class Derived : public Base`) Only case I know of though. – Fire Lancer Sep 12 '17 at 14:51
  • Why not just 'play()' given it's virtual? – Steve Sep 12 '17 at 14:53
  • @Steve While not immediately wrong, you might want to offer a little more explanation. E.g. Calling `play()` from within `DiceGame::play()` would lead to an unpleasant outcome. ;) – Disillusioned Sep 12 '17 at 14:55

1 Answers1

5
class DiceGame{
public:
    virtual void play() = 0;
};

class Knockout : public DiceGame{
public:
    virtual void play() { // Replace "virtual" with "override" here if your compiler supports "override" keyword.
        // This has the stuff I want to call
    }
};

int main()
{
    DiceGame *game = new Knockout();
    game->play();
    return 0;
}
KonstantinL
  • 667
  • 1
  • 8
  • 20
  • I'd suggest one improvement: In the `Knockout` subclass, use the `override` specifier instead of `virtual`. This feature is available as of C++11. – Disillusioned Sep 12 '17 at 15:51
  • @CraigYoung, you are right but I intentionally have not used `override` for this is beginner question. – KonstantinL Sep 12 '17 at 15:53
  • I believe teaching `override` is better for beginners: 1) The specifier names align better with the polymorphism concepts. 2) It avoids the trivial error case where override isn't called because the signature is slightly different. – Disillusioned Sep 12 '17 at 16:04
  • 1
    @CraigYoung, I have added note about "override". – KonstantinL Sep 12 '17 at 16:30