1

I spent hours and hours looking online but none had the same problem as me. Basically, I have a base class called MainShop and it has 3 derived classes which are SwordShop, SpellBookShop and BowShop. I want the base class to be able to call a function from one of the derived classes but no matter what i do, it doesn't seem to work! Here is my code:

#include "MainShop.h"
//BaseClass cpp

void MainShop::EnterShop(Hero& hero)
{
    //Display Choices
        switch (choice)
        {
            //Swords
            case 1: SwordShop::soldierShop(hero);//DOES NOT WORK!!
                        break;
            case 2: SpellBookShop::MageShop(hero);//Staffs
                        break;
            case 3: BowShop::ArcherShop(hero);//Bows
                        break;
            default: cout << "Error!, Please try again.";
                        MainShop::EnterShop(hero);


        }
}

I have two other derived classes, but its basically the same concept. I have a function in one of the derived classes and i would like to call it from the base class. This is one my derived classes:

//SwordShop derived cpp
#include "SwordShop.h"
void SwordShop::soldierShop(Hero& hero)
{
  /* some code here*/
}
Damian
  • 87
  • 2
  • 14
  • 1
    This is what virtual functions are for. – chris Dec 24 '13 at 02:18
  • Yep, hold a pointer to the base class and just call `.shop()` – yizzlez Dec 24 '13 at 02:19
  • I think it's great that you seem to take a structured OO approach to building and you definately should continue on this path as long as you feel you are learning or progressing towards a goal. For the long haul however, my experience has been that inheritance and polymorphism lead to inflexible programs and duplicated logic, especially when the project grows bigger. I've had compacter and more agile programs with type traits and composition. Admittedly the barrier to entry is higher so that's why I said it's not a bad idea to continue on this path for now. – Erik van Velzen Dec 24 '13 at 05:25

5 Answers5

3

It's not a good design to select specific sub-class instance in super-class methods, e.g., by dynamic_cast, due to runtime overhead, and future maintenance, etc.

You can offload the burden of such switch-case logic to virtual functions which are designed by the language to call a specific instance via base class pointer/reference.

For example:

class MainShop
{
public:
   virtual void EnterShop(Hero &hero) = 0;
};

class SwordShop: public MainShop
{
   void EnterShop(Hero &hero)
   {
      soldierShop(hero);
   }
};

class SpellBookShop: public MainShop
{
   void EnterShop(Hero &hero)
   {
      MageShop(hero);
   }
};

int main()
{
   ...
   MainShop *shop = new SwordShop;
   // calling soldierShop
   shop->EnterShop(hero);
   ..
   shop = new SpellBookShop;
   // calling MageShop
   shop->EnterShop(hero);
   ...
}
Eric Z
  • 14,327
  • 7
  • 45
  • 69
  • oh okay i kind of under now! Very clear! but lets say i have a hero class and inside that i have a function called gameplay. In the main i will declare the hero instance obviously and call gameplay. Inside gameplay i want to be able to call these shops, which is why i originally tried a switch statement. How can i do this without declaring each instance of every derived class in main? – Damian Dec 24 '13 at 02:58
  • That case, you need pass shop instance into gameplay anyway, since you are NOT calling static methods of shop objects, are you? Then you can pass the base class pointer/ref to gameplay as its argument. – Eric Z Dec 24 '13 at 03:02
  • okay so in the main.cpp it will be something like this then? Hero hero; and then hero.gameplay(MainShop& shop); and inside gameplay i will have the switch statement? – Damian Dec 24 '13 at 03:21
  • Inside gameplay, call the virtual function: `shop->..` – Eric Z Dec 24 '13 at 03:45
1

I guess you could try something like:

Derived* derived = dynamic_cast<Derived*>(this);
if (derived) {
    // this is of Derived type
} else {
    // this is of base type but not Derived
}

though as suggested you'd better use virtual function, since its the right use case:

class Base {
public:
    virtual void someMethod() = 0;

    void anotherMethods() {
        someMethod(); // determined by implementation in derived class
    }
};

class Derived1 : public Base {
    virtual void someMethod() override {
        // body
    }
};

class Derived2 : public Base {
    virtual void someMethod() override {
        // body
    }
};

Better readability, less error prone, much more sane.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
1

If you need to call EnterShop from any shop object (SwordShop etc.) then overriding a virtual function in the base class is the way to go.

class MainShop
{
     ...
     virtual void process_hero(Hero& hero)
     {
          // add default implementation or set as pure virtual
     }
     ...
};

void MainShop::EnterShop(Hero& hero)
{
    process_hero(hero);
}

class SwordShop: public MainShop
{
public:
    void process_hero(hero)
    {
        soldierShop(hero);
    }
};

...

However, it looks to me like you want a manager object to invoke the functions depending on the 'choice' variable. If this is the case, use composition instead of inheritance.

Prefer composition over inheritance?

Community
  • 1
  • 1
bancsy
  • 142
  • 1
  • 6
  • i looked at composition but i had no idea what was going on haha. I am still not that experienced in c++, can you give me an example of using composition with my code, to better understand the concept? – Damian Dec 24 '13 at 03:13
0

How about something like this? Obviously you must implement the .shop() function:

MainShop *ms;
switch(input){
    case 1:
    ms = new soldierShop(); break;
    case 2:
    ms = new MageShop(); break
    case 3:
    ms = new ArcherShop(); break;
}
ms.shop();
yizzlez
  • 8,757
  • 4
  • 29
  • 44
0

There are 2 options usually used to achieve the required functionality:

  1. use dynamic_cast<> to promote this pointer to the desired derived type and call whatever you want if cast succeeds.
  2. use templated base class in conjunction with curiously recurring template pattern - basically, pass the desired derived type as template argument to base class (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
oakad
  • 6,945
  • 1
  • 22
  • 31
  • or virtual functions? – djechlin Dec 24 '13 at 02:48
  • Nope. :) Virtual functions give you no control at which derived instance you're calling. In many cases you need to call something specific (which is what OP may have been asking). – oakad Dec 24 '13 at 02:49
  • 99% sure *if* OP needs that, it's because of terrible design. OP needs a virtual function, and if not, a refactor. If you disagree with me I'd strongly suggest explaining the situations your solution is good practice, otherwise the answer is likely to mislead more than anything. – djechlin Dec 24 '13 at 03:01
  • what is OP? and if i go with option 2 I will have to change my entire project, plus i am not really that experienced with c++ so it will take me a long time to grasp it. Option 1 however looks interesting. Can you give me an example of how to use option 1? – Damian Dec 24 '13 at 03:23
  • I agree this is not a solution to the problem of the OP but I'm upvoting to get rid of the -1 since technically these are the ways to "call a function of a derived class inside the base class". – Erik van Velzen Dec 24 '13 at 05:10