Reputation: 301
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
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.
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