Sku Sku
Sku Sku

Reputation: 301

How can I assure a pure virtual method is called from my derived class?

I have the following situation:

#include <iostream>

class Base{
  public:
    Base() = default;
    virtual void make_sure_im_called() = 0;
};

class Child : public Base {
  public:
    virtual void make_sure_im_called()
    {
      std::cout << "I was called as intended." << std::endl;
    };
}

It is so that I want every class that derives from Base to implement make_sure_im_called() (which is successfully done by making it pure virtual). But how can I assert that someone deriving a new class from Base is also forced to call the function? It seems that everything I try from the base class will fail because of the missing implementation.

Upvotes: 4

Views: 101

Answers (1)

JVApen
JVApen

Reputation: 11317

In C++ there is no build-in construct which does what you want, though, you can always enforce it yourself.

#include <iostream>

class Base{
  public:
    Base() = default;
    void make_sure_im_called() {
       before_make_sure_im_called();
       // Your own code
       after_make_sure_im_called();
    }
  protected:
    // Hooks to be implemented
    virtual void before_make_sure_im_called() = 0;
    virtual void after_make_sure_im_called() = 0;
};

class Child : public Base {
  protected:
    virtual void before_make_sure_im_called() override
    {
      std::cout << "I was called as intended." << std::endl;
    };
    virtual void after_make_sure_im_called() override {}
}

This results in 2 virtual calls (most of the time, you can survive with 1 of them). If someone calls make_sure_im_called, this now will call the pure virtual calls.

By making them protected, the chance of them being called is reduced as only derived classes can access them.

Enforcing this method being called in the lifespan of the instance.

The method make_sure_im_called can't be called from within the constructor of Base. There is no construction which can enforce this, though, you could let the program crash if this was not the case.

#include <iostream>

class Base{
  public:
    Base() = default;
    ~Base() { assert(_initialized && "Some message"); }
    void make_sure_im_called() {
       before_make_sure_im_called();
       // Your own code
       after_make_sure_im_called();
       _initialized = true;
    }
  protected:
    // Hooks to be implemented
    virtual void before_make_sure_im_called() = 0;
    virtual void after_make_sure_im_called() = 0;

  private:
      bool _initialized{false};
};

class Child : public Base {
  protected:
    virtual void before_make_sure_im_called() override {};
    virtual void after_make_sure_im_called() override {}
}

By keeping the _initialized member, you can keep track of the method being called. In the Dtor, you can assert on this and crash the program if this is false (debug-builds only?). Exercise to the reader: get copy/move-construction/assignment right.

The solution might not be that elegant, though, at least it will be better than having nothing at all. One could even document this as part of the API.

Upvotes: 5

Related Questions