Abstract class, abstract method parameters and inheritance - c++

I joined a research project in which the OOQP library is used. It uses an abstract class OoqpVector (inherited by several subclasses) and a number of methods, such as:
virtual double dotProductWith(OoqpVector& v) = 0
This method is implemented by subclasses SimpleVector and DistributedVector. Because of genericity, OoqpVector::dotProductWith allows all possible combinations:
SimpleVector.dotProductWith(SimpleVector)
DistributedVector.dotProductWith(DistributedVector)
SimpleVector.dotProductWith(DistributedVector)
DistributedVector.dotProductWith(SimpleVector)
However in practice, the method is called on vectors of the same type only (combinations 1 and 2). Therefore, the authors implemented SimpleVector::dotProductWith(OoqpVector&) and DistributedVector::dotProductWith(OoqpVector&) by dynamically casting the parameter to the current type.
Although this works, I find it a bit ugly and wonder if we can implement the same behavior without casts.
An option would be to get rid of OoqpVector::dotProductWith, declare the specialized methods SimpleVector::dotProductWith(SimpleVector&) and DistributedVector::dotProductWith(DistributedVector&), and force the calling methods to impose the two vector types to be equal. However, our code uses a bunch of OoqpVectors everywhere and is relatively generic, so this might be difficult to achieve.
Do you see a way to fix that?
Best,
Charlie

Related

C++ Inheritance & Virtual Functions Where Base Parameters require Replacement with Derived Ones

I have looked high and low for answers to this question - here on this forum and on the general internet. While I have found posts discussing similar topics, I am at a point where I need to make some design choices and am wondering if I am going about it the right way, which is as follows:
In C++ I have created 3 data structures: A linked list, a binary tree and a grid. I want to be able to store different classes in these data structures - one may be a class to manipulate strings, another numbers, etc. Now, each of these classes, assigned to the nodes, has the ability to perform and handle comparison operations for the standard inequality operators.
I thought C++ inheritance would provide the perfect solution to the matter - it would allow for a base "data class" (the abstract class) and all the other data classes, such as JString, to inherit from it. So the data class would have the following inequality method:
virtual bool isGreaterThan(const dataStructure & otherData) const = 0;
Then, JString will inherit from dataStructure and the desire would be to override this method, since isGreaterThan will obviously have a different meaning depending on the class. However, what I need is this:
virtual bool isGreaterThan(const JString & otherData) const;
Which, I know will not work since the parameters are of a different data type and C++ requires this for the overriding of virtual methods. The only solution I could see is doing something like this in JString:
virtual bool isGreaterThan(const dataStructure & otherData);
{
this->isGreaterThanJString(dynamic_cast<const JString&>(theSourceData));
};
virtual bool isGreaterThanJString(const JString & otherData) const;
In other words, the overriding method just calls the JString equivalent, down-casting otherData to a JString object, since this will always be true and if not, it should fail regardless.
My question is this: Does this seem like an acceptable strategy or am I missing some ability in C++. I have used templates as well, but I am trying to avoid this as I find debugging becomes very difficult. The other option would be to try a void* that can accept any data type, but this comes with issues as well and shifts the burden onto the code resulting in lengthier classes.
The LSP means operations on a reference to base class must work and have the same semantics as operations on both base and derived class instances when those operations are referentially polymorphic.
Your example fails this test. The base isGreaterThan claims to work on all dataStructure, but it does not.
I would make the dataStructure argument types templates in your containers. Then you know the concrete type of the stored data.
Look at std list for an idea of what a linked list template might look like.
I will now go onto complex additional steps you can do in the 0.1% of cases where the above advice is not correct.
If this causes issues, because of template bloat, you could create a polymorphic container that enforces the type of the stored data, either with a thin template wrapper or runtime tests. Once stored, you blindly cast to the known stored type, and store how to copy/compare/etc said type either in a C or C++ style polymorphic method.
Here is an 8 year old fun talk about this approach: https://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil

Design Pattern for a very long base class

If I have 8 long methods that will be shared among 4 child classes (not all of them will be using all the methods) some will be use only 2 others 4, etc.
If I create a base class and each of the 4 child classes inherit from the base class then the problem is solved but I am trying to avoid using a very long base class.
I can try to divide the base class in more classes depending on how they are used and then use multiple inheritance, this is another solution.
Is there any other pattern to solve this problem?? What would be the optimal?
From the way you have posed the question, the first thing you need to seriously consider is whether you need classes at all.
One trap that beginners often fall into is believing that everything has to be in a class. While it is true that some languages require that, it is an option, but is not necessarily required - and can even be a really bad idea - in C++.
Unless there is an actual "is-a" relationship between the classes (e.g. the base class represents a Dog and derived classes represent types of dog) it is probably better not to use inheritance at all.
[There are circumstances where a class hierarchy is appropriate, even if there isn't an "is-a" relationship - but, if your situation was like that, you almost certainly wouldn't need to ask the question you have.]
Instead, I'd simply define eight non-member functions (i.e. that are not members of a class) with appropriate arguments and return type. The arguments and return value (if any) can be used both to pass information to the function, or to pass information back.
The four classes then call the functions as needed. From your description, however, it is not even clear that you need those four classes. Possibly all that is needed is a set of functions that are implemented by calling your "8 long methods". Those "8 long methods" can be implemented locally to a source file, if you need to prevent other code from calling them.
Generally speaking, aim to make your design as simple as possible. If that is achievable without having a class hierarchy, or without defining any classes at all, then don't use classes.

Dependency inversion (from S.O.L.I.D principles) in C++

After reading and watching much about SOLID principles I was very keen to use these principles in my work (mostly C++ development) since I do think they are good principles and that they indeed will bring much benefit to the quality of my code, readability, testability, reuse and maintainability.
But I have real hard time with the 'D' (Dependency inversion).
This principal states that:
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.
Let me explain by example:
Lets say I am writing the following interface:
class SOLIDInterface {
//usual stuff with constructor, destructor, don't copy etc
public:
virtual void setSomeString(const std::string &someString) = 0;
};
(for the sake of simplicity please ignore the other things needed for a "correct interface" such as non virutal publics, private virtuals etc, its not part of the problem.)
notice, that setSomeString() is taking an std::string.
But that breaks the above principal since std::string is an implementation.
Java and C# don't have that problem since the language offers interfaces to all the complex common types such as string and containers.
C++ does not offer that.
Now, C++ does offer the possibility to write this interface in such a way that I could write an 'IString' interface that would take any implementation that will support an std::string interface using type erasure
(Very good article: http://www.artima.com/cppsource/type_erasure.html)
So the implementation could use STL (std::string) or Qt (QString), or my own string implementation or something else.
Like it should be.
But this means, that if I (and not only I but all C++ developers) want to write C++ API which obeys SOLID design principles ('D' included), I will have to implement a LOT of code to accommodate all the common non natural types.
Beyond being not realistic in terms of effort, this solution has other problems such as - what if STL changes?(for this example)
And its not really a solution since STL is not implementing IString, rather IString is abstracting STL, so even if I were to create such an interface the principal problem remains.
(I am not even getting into issues such as this adds polymorphic overhead, which for some systems, depending on size and HW requirements may not be acceptable)
So may question is:
Am I missing something here (which I guess the true answer, but what?), is there a way to use Dependency inversion in C++ without writing a whole new interface layer for the common types in a realistic way - or are we doomed to write API which is always dependent on some implementation?
Thanks for your time!
From the first few comments I received so far I think a clarification is needed:
The selection of std::string was just an example.
It could be QString for that matter - I just took STL since it is the standard.
Its not even important that its a string type, it could be any common type.
I have selected the answer by Corristo not because he explicitly answered my question but because the extensive post (coupled with the other answers) allowed me to extract my answer from it implicitly, realizing that the discussion tends to drift from the actual question which is:
Can you implement Dependency inversion in C++ when you use basic complex types like strings and containers and basically any of the STL with an effort that makes sense. (and the last part is a very important element of the question).
Maybe I should have explicitly noted that I am after run-time polymorphism not compile time.
The clear answer is NO, its not possible.
It might have been possible if STL would have exposed abstract interfaces to their implementations (if there are indeed reasons that prevent the STL implementations to derive from these interfaces (say, performance)) then it still could have simply maintained these abstract interfaces to match the implementations).
For types that I have full control over, yes, there is no technical problem implementing the DIP.
But most likely any such interface (of my own) will still use a string or a container, forcing it to use either the STL implementation or another.
All the suggested solutions below are either not polymorphic in runtime, or/and are forcing quiet a some coding around the interface - when you think you have to do this for all these common types the practicality is simply not there.
If you think you know better, and you say it is possible to have what I described above then simply post the code proving it.
I dare you! :-)
Note that C++ is not an object-oriented programming language, but rather lets the programmer choose between many different paradigms. One of the key principles of C++ is that of zero-cost abstractions, which in particular entails to build abstractions in such a way that users don't pay for what they don't use.
The C#/Java style of defining interfaces with virtual methods that are then implemented by derived classes don't fall into that category though, because even if you don't need the polymorphic behavior, were std::string implementing a virtual interface, every call of one of its methods would incur a vtable lookup. This is unacceptable for classes in the C++ standard library supposed to be used in all kinds of settings.
Defining interfaces without inheriting from an abstract interface class
Another problem with the C#/Java approach is that in most cases you don't actually care that something inherits from a particular abstract interface class and only need that the type you pass to a function supports the operations you use. Restricting accepted parameters to those inheriting from a particular interface class thus actually hinders reuse of existing components, and you often end up writing wrappers to make classes of one library conform to the interfaces of another - even when they already have the exact same member functions.
Together with the fact that inheritance-based polymorphism typically also entails heap allocations and reference semantics with all its problems regarding lifetime management, it is best to avoid inheriting from an abstract interface class in C++.
Generic templates for implicit interfaces
In C++ you can get compile-time polymorphism through templates.
In its simplest form, the interface that an object used in a templated function or class need to conform to is not actually specified in C++ code, but implied by what functions are called on them.
This is the approach used in the STL, and it is really flexible. Take std::vector for example. There the requirements on the value type T of objects you store in it are dependent on what operations you perform on the vector. This allows e.g. to store move-only types as long as you don't use any of the operations that need to make a copy. In such a case, defining an interface that the value types needs to conform to would greatly reduce the usefulness of std::vector, because you'd either need to remove methods that require copies or you'd need to exclude move-only types from being stored in it.
That doesn't mean you can't use dependency inversion, though: The common Button-Lamp example for dependency inversion implemented with templates would look like this:
class Lamp {
public:
void activate();
void deactivate();
};
template <typename T>
class Button {
Button(T& switchable)
: _switchable(&switchable) {
}
void toggle() {
if (_buttonIsInOnPosition) {
_switchable->deactivate();
_buttonIsInOnPosition = false;
} else {
_switchable->activate();
_buttonIsInOnPosition = true;
}
}
private:
bool _buttonIsInOnPosition{false};
T* _switchable;
}
int main() {
Lamp l;
Button<Lamp> b(l)
b.toggle();
}
Here Button<T>::toggle implicitly relies on a Switchable interface, requiring T to have member functions T::activate and T::deactivate. Since Lamp happens to implement that interface it can be used with the Button class. Of course, in real code you would also state these requirements on T in the documentation of the Button class so that users don't need to look up the implementation.
Similarly, you could also declare your setSomeString method as
template <typename String>
void setSomeString(String const& string);
and then this will work with all types that implement all the methods you used in the implementation of setSomeString, hence only relying on an abstract - although implicit - interface.
As always, there are some downsides to consider:
In the string example, assuming you only make use of .begin() and .end() member functions returning iterators that return a char when dereferenced (e.g. to copy it into the classes' local, concrete string data member), you can also accidentally pass a std::vector<char> to it, even though it isn't technically a string. If you consider this a problem is arguable, in a way this can also be seen as the epitome of relying only on abstractions.
If you pass an object of a type that doesn't have the required (member) functions, then you can end up with horrible compiler error messages that make it very hard to find the source of the error.
Only in very limited cases it is possible to separate the interface of a templated class or function from its implementation, as is typically done with separate .h and .cpp files. This can thus lead to longer compile times.
Defining interfaces with the Concepts TS
if you really care about types used in templated functions and classes to conform to a fixed interface, regardless of what you actually use, there are ways to restrict the template parameters only to types conforming to a certain interface with std::enable_if, but these are very verbose and unreadable. In order to make this kind of generic programming easier, the Concepts TS allows to actually define interfaces that are checked by the compiler and thus greatly improves diagnostics. With the Concepts TS, the Button-Lamp example from above translates to
template <typename T>
concept bool Switchable = requires(T t) {
t.activate();
t.deactivate();
};
// Lamp as before
template <Switchable T>
class Button {
public:
Button(T&); // implementation as before
void toggle(); // implementation as before
private:
T* _switchable;
bool _buttonIsInOnPosition{false};
};
If you can't use the Concepts TS (it is only implemented in GCC right now), the closest you can get is the Boost.ConceptCheck library.
Type erasure for runtime polymorphism
There is one case where compile-time polymorphism doesn't suffice, and that is when the types you pass to or get from a particular function aren't fully determined at compile-time but depend on runtime parameters (e.g. from a config file, command-line arguments passed to the executable or even the value of a parameter passed to the function itself).
If you need to store objects (even in a variable) of a type dependent on runtime parameters, the traditional approach is to store pointers to a common base class instead and to use dynamic dispatch via virtual member functions to get the behavior you need. But this still suffers from the problem described before: You can't use types that effectively do what you need but were defined in an external library, and thus don't inherit from the base class you defined. So you have to write a wrapper class.
Or you do what you described in your question and create a type-erasure class.
An example from the standard library is std::function. You declare only the interface of the function and it can store arbitrary function pointers and callables that have that interface. In general, writing a type erasure class can be quite tedious, so I refrain from giving an example of a type-erasing Switchable here, but I can highly recommend Sean Parent's talk Inheritance is the base class of evil, where he demonstrates the technique for "Drawable" objects and explores what you can build on top of it in just over 20 minutes.
There are libraries that help writing type-erasure classes though, e.g. Louis Dionne's experimental dyno, where you define the interface via what he calls "concept maps" directly in C++ code, or Zach Laine's emtypen which uses a python tool to create the type erasure classes from a C++ header file you provide. The latter also comes with a CppCon talk describing the features as well as the general idea and how to use it.
Conclusion
Inheriting from a common base class just to define interfaces, while easy, leads to many problems that can be avoided using different approaches:
(Constrained) templates allow for compile-time polymorphism, which is sufficient for the majority of cases, but can lead to hard-to-understand compiler errors when used with types that don't conform to the interface.
If you need runtime polymorphism (which actually is rather rare in my experience), you can use type-erasure classes.
So even though the classes in the STL and other C++ libraries rarely derive from an abstract interface, you can still apply dependency inversion with one of the two methods described above if you really want to.
But as always, use good judgment on a case-by-case basis whether you really need the abstraction or if it is better to simply use a concrete type. The string example you brought up is one where I'd go with concrete types, simply because the different string classes don't share a common interface (e.g. std::string has .find(), but QStrings version of the same function is called .contains()). It might be just as much effort to write wrapper classes for both as it is to write a conversion function and to use that at well-defined boundaries within the project.
Ahh, but C++ lets you write code that is independent of a particular implementation without actually using inheritance.
std::string itself is a good example... it's actually a typedef for std::basic_string<char, std::char_traits<char>, std::allocator<char>>. Which allows you to create strings using other allocators if you choose (or mock the allocator object in order to measure number of calls, if you like). There just isn't any explicit interface like an IAllocator, because C++ templates use duck-typing.
A future version of C++ will support explicit description of the interface a template parameter must adhere to -- this feature is called concepts -- but just using duck-typing enables decoupling without requiring redundant interface definitions.
And because C++ performs optimization after instantiation of templates, there's no polymorphic overhead.
Now, when you do have virtual functions, you'll need to commit to a particular type, because the virtual-table layout doesn't accommodate use of templates each of which generates an arbitrary number of instances each of which require separate dispatch. But when using templates, you'll won't need virtual functions nearly as much as e.g. Java does, so in practice this isn't a big problem.

Vector of pointers to base type, find all instances of a given derived type stored in a base type

Suppose you have a base class inside of a library:
class A {};
and derived classes
class B: public A {};
class C: public A {};
Now Instances of B and C are stored in a std::vector of boost::shared_ptr<A>:
std::vector<boost::shared_ptr<A> > A_vec;
A_vec.push_back(boost::shared_ptr<B>(new B()));
A_vec.push_back(boost::shared_ptr<C>(new C()));
Adding instances of B and C is done by a user, and there is no way to determine in advance the order, in which they will be added.
However, inside of the library, there may be a need to perform specific actions on B and C, so the pointer to the base class needs to be casted to B and C.
I can of course do "trial and error" conversions, i.e. try to cast to Band C(and any other derivative of the base class), until I find a conversion that doesn't throw. However, this method seems very crude and error-prone, and I'm looking for a more elegant (and better performing) way.
I am looking for a solution that will also work with C++98, but may involve boost functionality.
Any ideas ?
EDIT:
O.k., thanks for all the answers so far!
I'd like to give some more details regarding the use-case. All of this happens in the context of parametric optimization.
Users define the optimization problem by:
Specifying the parameters, i.e. their types (e.g. "constrained double", "constrained integer", "unconstrained double", "boolean", etc.) and initial values
Specifying the evaluation function, which assigns one or more evaluations (double values) to a given parameter set
Different optimization algorithms then act on the problem definitions, including their parameters.
There is a number of predefined parameter objects for common cases, but users may also create their own parameter objects, by deriving from one of my base classes. So from a library perspective, apart from the fact that the parameter objects need to comply with a given (base-class) API, I cannot assume much about parameter objects.
The problem definition is a user-defined C++-class, derived from a base-class with a std::vector interface. The user adds his (predefined or home-grown) parameter objects and overloads a fitness-function.
Access to the parameter objects may happen
from within the optimization algorithms (usually o.k., even for home-grown parameter objects, as derived parameter objects need to provide access functions for their values).
from within the user-supplied fitness function (usually o.k., as the user knows where to find which parameter object in the collection and its value can be accessed easily)
This works fine.
There may however be special cases where
a user wants to access specifics of his home-grown parameter types
a third party has supplied the parameter structure (this is an Open Source library, others may add code for specific optimization problems)
the parameter structure (i.e. which parameters are where in the vector) may be modified as part of the optimization problem --> example: training of the architecture of a neural network
Under these circumstances it would be great to have an easy method to access all parameter objects of a given derived type inside of the collection of base types.
I already have a templated "conversion_iterator". It iterates over the vector of base objects and skips those that do not comply with the desired target type. However, this is based on "trial and error" conversion (i.e. I check whether the converted smart pointer is NULL), which I find very unelegant and error-prone.
I'd love to have a better solution.
NB: The optimization library is targetted at use-cases, where the evaluation step for a given parameter set may last arbitrarily long (usually seconds, possibly hours or longer). So speed of access to parameter types is not much of an issue. But stability and maintainability is ...
There’s no better general solution than trying to cast and seeing whether it succeeds. You can alternatively derive the dynamic typeid and compare it to all types in turn, but that is effectively the same amount of work.
More fundamentally, your need to do this hints at a design problem: the whole purpose of a base class is to be able to treat children as if they were parents. There are certain situations where this is necessary though, in which case you’d use a visitor to dispatch them.
If possible, add virtual methods to class A to do the "specific actions on B and C".
If that's not possible or not reasonable, use the pointer form of dynamic_cast, so there are no exceptions involved.
for (boost::shared_ptr<A> a : A_vec)
{
if (B* b = dynamic_cast<B*>(a.get()))
{
b->do_something();
}
else if (C* c = dynamic_cast<C*>(a.get()))
{
something_else(*c);
}
}
Adding instances of B and C is done by a user, and there is no way to determine in advance the order, in which they will be added.
Okay, so just put them in two different containers?
std::vector<boost::shared_ptr<A> > A_vec;
std::vector<boost::shared_ptr<B> > B_vec;
std::vector<boost::shared_ptr<C> > C_vec;
void add(B * p)
{
B_vec.push_back(boost::shared_ptr<B>(p));
A_vec.push_back(b.back());
}
void add(C * p)
{
C_vec.push_back(boost::shared_ptr<C>(p));
A_vec.push_back(c.back());
}
Then you can iterate over the Bs or Cs to your hearts content.
I would suggest to implement a method in the base class (e.g. TypeOf()), which will return the type of the particular object. Make sure you define that method as virtual and abstract so that you will be enforced to implement in the derived types. As for the type itself, you can define an enum for each type (e.g. class).
enum class ClassType { ClassA, ClassB, ClassC };
This answer might interest you: Generating an interface without virtual functions?
This shows you both approaches
variant w/visitor in a single collection
separate collections,
as have been suggested by others (Fred and Konrad, notably). The latter is more efficient for iteration, the former could well be more pure and maintainable. It could even be more efficient too, depending on the usage patterns.

Is there any way to avoid declaring virtual methods when storing (children) pointers?

I have run into an annoying problem lately, and I am not satisfied with my own workaround: I have a program that maintains a vector of pointers to a base class, and I am storing there all kind of children object-pointers. Now, each child class has methods of their own, and the main program may or not may call these methods, depending on the type of object (note though that they all heavily use common methods of the base class, so this justify inheritance).
I have found useful to have an "object identifier" to check the class type (and then either call the method or not), which is already not very beautiful, but this is not the main inconvenience. The main inconvenience is that, if I want to actually be able to call a derived class method using the base class pointer (or even just store the pointer in the pointer array), then one need to declare the derived methods as virtual in the base class.
Make sense from the C++ coding point of view.. but this is not practical in my case (from the development point of view), because I am planning to create many different children classes in different files, perhaps made by different people, and I don't want to tweak/maintain the base class each time, to add virtual methods!
How to do this? Essentially, what I am asking (I guess) is how to implement something like Objective-C NSArrays - if you send a message to an object that does not implement the method, well, nothing happens.
regards
Instead of this:
// variant A: declare everything in the base class
void DoStuff_A(Base* b) {
if (b->TypeId() == DERIVED_1)
b->DoDerived1Stuff();
else if if (b->TypeId() == DERIVED_2)
b->DoDerived12Stuff();
}
or this:
// variant B: declare nothing in the base class
void DoStuff_B(Base* b) {
if (b->TypeId() == DERIVED_1)
(dynamic_cast<Derived1*>(b))->DoDerived1Stuff();
else if if (b->TypeId() == DERIVED_2)
(dynamic_cast<Derived2*>(b))->DoDerived12Stuff();
}
do this:
// variant C: declare the right thing in the base class
b->DoStuff();
Note there's a single virtual function in the base per stuff that has to be done.
If you find yourself in a situation where you are more comfortable with variants A or B then with variant C, stop and rethink your design. You are coupling components too tightly and in the end it will backfire.
I am planning to create many different children classes in different
files, perhaps made by different people, and I don't want to
tweak/maintain the base class each time, to add virtual methods!
You are OK with tweaking DoStuff each time a derived class is added, but tweaking Base is a no-no. May I ask why?
If your design does not fit in either A, B or C pattern, show what you have, for clairvoyance is a rare feat these days.
You can do what you describe in C++, but not using functions. It is, by the way, kind of horrible but I suppose there might be cases in which it's a legitimate approach.
First way of doing this:
Define a function with a signature something like boost::variant parseMessage(std::string, std::vector<boost::variant>); and perhaps a string of convenience functions with common signatures on the base class and include a message lookup table on the base class which takes functors. In each class constructor add its messages to the message table and the parseMessage function then parcels off each message to the right function on the class.
It's ugly and slow but it should work.
Second way of doing this:
Define the virtual functions further down the hierarchy so if you want to add int foo(bar*); you first add a class that defines it as virtual and then ensure every class that wants to define int foo(bar*); inherit from it. You can then use dynamic_cast to ensure that the pointer you are looking at inherits from this class before trying to call int foo(bar*);. Possible these interface adding classes could be pure virtual so they can be mixed in to various points using multiple inheritance, but that may have its own problems.
This is less flexible than the first way and requires the classes that implement a function to be linked to each other. Oh, and it's still ugly.
But mostly I suggest you try and write C++ code like C++ code not Objective-C code.
This can be solved by adding some sort of introspection capabilities and meta object system. This talk Metadata and reflection in C++ — Jeff Tucker demonstrates how to do this using c++'s template meta programming.
If you don't want to go to the trouble of implementing one yourself, then it would be easier to use an existing one such as Qt's meta object system. Note that this solution does not work with multiple inheritance due to limitations in the meta object compiler: QObject Multiple Inheritance.
With that installed, you can query for the presence of methods and call them. This is quite tedious to do by hand, so the easiest way to call such a methods is using the signal and slot mechanism.
There is also GObject which is quite simmilar and there are others.
If you are planning to create many different children classes in different files, perhaps made by different people, and also I would guess you don't want to change your main code for every child class. Then I think what you need to do in your base class is to define several (not to many) virtual functions (with empty implementation) BUT those functions should be used to mark a time in the logic where they are called like "AfterInseart" or "BeforeSorting", Etc.
Usually there are not to many places in the logic you wish a derived classes to perform there own logic.