Search code examples
c++abstract-classvirtual

Call through the base class abstract method


I have an interface from which a user derives multiple classes which I have no knowledge of but still I want to call these derived classes common method Run().

The Event class is intended to be an interface so I know how to call my unknown UserEvents derived class, since they all must have that Run() method implemented.

I currently have some code and get an error that CallEvent can't allocate an abstract Event. I understand the error, but don't know how I can go about and execute this correctly.

Here's some minimal code example (WandBox):

#include <iostream>

class Event
 {
 public: 
      virtual void Run(int Param) = 0;
 };

 // This is a user event and I have no idea what the class name is,
 // but I still have to call it's method Run() that is common to the interface "Event"
 class UserEvent : public Event
 {
 public:
      virtual void Run(int Param) { std::cout << "Derived Event Dispatched " << Param << std::endl;};
 };

 // This parameter is of pure abstract base class Event because
 // I have no idea what my user class is called.
 void CallEvent(Event WhatEvent)
 {
      WhatEvent.Run(123);
 };

 int main()
 {
      std::cout << "Hello World!" << std::endl;
      UserEvent mE;
      CallEvent(mE);
 }

Solution

  • I took your sample code (Like so) and tried to make it running (for illustration):

    #include <iostream>
    
    class Event {
      public: 
        virtual void Run(int Param) = 0;
    };
    
    // This is a user event and I have no idea what the class name is,
    // but I still have to call it's method Run() that is common to the interface "Event"
    class UserEvent: public Event {
      public:
        virtual void Run(int Param)
        {
          std::cout << "Derived Event Dispatched " << Param << std::endl;
        }
    };
    
    // This parameter is of pure abstract base class Event because
    // I have no idea what my user class is called.
    void CallEvent(Event *WhatEvent)
    {
      std::cout << "in CallEvent(Event *WhatEvent):" << std::endl;
      // Huh? WhatEvent = new Event();
      // wrong: WhatEvent.Run(123);
      // Instead, use ->.
      // For pointers, check for non-nullptr is very reasonable:
      WhatEvent->Run(123);
      // obsolete: delete WhatEvent;
    }
    
    // second approach using a reference (as recommended in comments):
    void CallEvent(Event &WhatEvent)
    {
      std::cout << "in CallEvent(Event &WhatEvent):" << std::endl;
      WhatEvent.Run(123); // for references - select operator . is fine
    }
    
    int main()
    {
      std::cout << "Hello World!" << std::endl;
      /* nullptr does not make sense:
       * UserEvent *mE = nullptr;
       * Go back to original approach:
       */
      UserEvent mE;
      CallEvent(&mE); // calling the first (with Event*)
      CallEvent(mE); // calling the second (with Event&)
      return 0;
    }
    

    Now, it is compilable and runnable. Output:

    Hello World!
    in CallEvent(Event *WhatEvent):
    Derived Event Dispatched 123
    in CallEvent(Event &WhatEvent):
    Derived Event Dispatched 123
    

    (Life demo on ideone)

    I annotated every modification in comments inside the sample code.