Say you have a base class with multiple functions, like
virtual int func1();
virtual int func2();
virtual int func3();
virtual int func4();
There's a potential problem already, even without mentioning the derived classes. You've declared Base::func1()
, etc., but you haven't defined those functions. That's what the linker error was complaining about.
If it doesn't make sense to define those functions at the base class level, you need to declare those functions as "pure virtual" by inserting = 0
before the semicolons that terminate the function declarations:
class Base {
public:
virtual int func1() = 0;
virtual int func2() = 0;
virtual int func3() = 0;
virtual int func4() = 0;
...
};
(Note: I made those pure virtual functions public on purpose. I'll get to that later.)
What this does is to say that those functions can be used on any class that derives from the base class, but at the same time, it doesn't make sense to define those functions at the base class level. If you do this, those functions must be defined in the child classes (or in the sub-child classes, or the sub-...-sub-child classes). A class with undefined pure virtual functions is not instantiable.
What if you want Child1
to have functions func1()
and func2()
, but not func3()
or func4()
? The functions are callable at the base class level, but not at the child class level. This violates the Liskov substitution principle. This is a very big sign that your design is wrong.
An alternative is to provide default implementations at the base class level (where that makes sense), and override them at the child class level (where this makes sense). Your Child1
can provide class-specific definitions of func1()
and func2()
that override the defaults provided in the base class.
Yet another alternative is to use multiple inheritance. Multiple inheritance can get you in deep trouble, but done right, there's nothing wrong with multiple inheritance.
Yet another alternative is to do something that subverts but does not violate Liskov substitution. For example, implement func3()
and func4()
in Child1
, but always throw an exception in these implementations. Don't do this.