سؤال

I've a question regarding a concept. First, I'm a mechanical engineer and not a programmer, thus I have some C++ knowledge but not much experience. I use the finite element method (FEM) to solve partial differential equations.

I have a base class Solver and two child linSolver, for linear FEM, and nlinSolver for non-linear FEM. The members and methods that both children share are in the base class. The base class members are all protected. Thus using inheritance makes the child classes "easy to use", like there weren't any inheritance or other boundaries. The base class itself, Solver, is incomplete, meaning only the children are of any use to me.

The concept works actually pretty good - but I think that having an unusable class is a bad design. In addition I read that protected inheritance is not preferred and should be avoided if possible. I think the last point don't really apply to my specific use, since I will never use it allow and any attempt to do so will fail (since it is incomplete).

The questions are:

  • Is it common to use inheritance to reduce double code even if the base class will be unusable?
  • What are alternatives or better solutions to such a problem?
  • Is protected inheritance really bad?

Thank you for your time. Dnaiel

هل كانت مفيدة؟

المحلول

Having "unusable" base classes is actually very common. You can have the base class to define a common interface usable by the classes that inherits the base-class. And if you declare those interface-functions virtual you can use e.g. references or pointers to the base-class and the correct function in the inherited class object will be called.

Like this:

class Base
{
public:
    virtual ~Base() {}

    virtual void someFunction() = 0;  // Declares an abstract function
};

class ChildA : public Base
{
public:
    void someFunction() { /* implementation here */ }
};

class ChildB : public Base
{
public:
    void someFunction() { /* other implementation here */ }
};

With the above classes, you can do

Base* ptr1 = new ChildA;
Base* ptr2 = new ChildB;

ptr1->someFunction();  // Calls `ChildA::someFunction`
ptr2->someFunction();  // Calls `ChildB::someFunction`

However this will not work:

Base baseObject;  // Compilation error! Base class is "unusable" by itself

While the (working) example above is simple, think about what you could do when passing the pointers to a function. Instead of having two overloaded functions each taking the actual class, you can have a single function which takes a pointer to the base class, and the compiler and runtime-system will make sure that the correct (virtual) functions are called:

void aGlobalFunction(Base* ptr)
{
    // Will call either `ChildA::someFunction` or `ChildB::someFunction`
    // depending on which pointer is passed as argument
    ptr->someFunction();
}

...

aGlobalFunction(ptr1);
aGlobalFunction(ptr2);

Even though the base-class is "unusable" directly, it still provides some functionality that is part of the core of how C++ can be (and is) used.

Of course, the base class doesn't have to be all interface, it can contain other common (protected) helper or utility functions that can be used from all classes that inherits the base class. Remember that inheritance is a "is-a" relationship between classes. If you have two different classes that both "is-a" something, then using inheritance is probably a very good solution.

نصائح أخرى

You should check the concept of Abstract class. It's designed to provide base class that cannot be instantiated. To do so you provide at least one method in the base class like this

virtual void f()=0;

Each child have to override the f function (or any pure virtual function from the base class) in order to be instantiable.

Don't think of the BaseClass as a class in its own right, but as an interface contract and some implementation help. Therefore, it should be abstract, if neccessary by declaring the dtor pure virtual but providing an implementation anyway. Some OO purists may frown upon any non-private element, but purity is not a good target.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top