Для простых случаев вы можете использовать вторую закрытую функцию-член для переопределяемого поведения:
class Base {
public:
void Draw() {
// Base-class functionality here
OverrideableDraw();
}
private:
virtual void OverrideableDraw() { }
};
class Derived : public Base {
private:
virtual void OverrideableDraw() {
// Derived-class functionality here
}
};
Для более сложных иерархий (например, когда у вас есть несколько уровней наследования), это невозможно, поскольку любой производный класс может переопределить любую виртуальную функцию-член (в C ++ нет final
). Обычно можно предположить, что каждый производный класс делает правильные вещи. Хотя я могу несколько раз подумать, что у меня возникли проблемы, потому что производный класс облажался с переопределением, эти случаи обычно довольно просто отлаживать.
Если вы действительно беспокоитесь об этом и действительно хотите гарантировать, что переопределения базового класса выполняются первыми, вы можете использовать что-то вроде этого, хотя это довольно дорого (по крайней мере, эта наивная реализация довольно дорога):
#include <functional>
#include <iostream>
#include <vector>
class Base {
public:
Base() {
RegisterDrawCallback(std::bind(&Base::DrawCallback, this));
}
void Draw() {
for (auto it(drawCallbacks_.begin()); it != drawCallbacks_.end(); ++it)
(*it)();
}
protected:
typedef std::function<void(void)> DrawCallbackType;
typedef std::vector<DrawCallbackType> DrawSequence;
void RegisterDrawCallback(DrawCallbackType f) {
drawCallbacks_.push_back(f);
}
private:
void DrawCallback() { std::cout << "Base" << std::endl; }
DrawSequence drawCallbacks_;
};
class Derived : public Base {
public:
Derived() {
RegisterDrawCallback(std::bind(&Derived::DrawCallback, this));
}
private:
void DrawCallback() { std::cout << "Derived" << std::endl; }
};
class DerivedDerived : public Derived {
public:
DerivedDerived() {
RegisterDrawCallback(std::bind(&DerivedDerived::DrawCallback, this));
}
private:
void DrawCallback() { std::cout << "DerivedDerived" << std::endl; }
};
[Это всего лишь один вариант; кто-то другой может, вероятно, придумать гораздо более элегантное решение. Лично я бы просто позаботился о том, чтобы функции виртуальных членов были хорошо документированы, и оставил все как есть.]