Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selectively inheriting from any of multiple classes at runtime

I'm doing scientific computing and I'm beginner in c++. MyNLP is a class which contain all the problem data and methods. I'm using third party libraries for numerical optimization. Each third party is a specific algorithm to solve my problem. In order to use each library, my MyNLP class need to inherit corresponding class from third party library.

For example,

Class MyNLP :public IPOPT
{
};

enable me to use IPOPT algorithm to solve my problem. Similarly,

class MyNLP: public SQP
{
};

enable me to use SQP algorithm.

But in my case, only at the run-time, program decides which class it should inherit. I have to inherit either one of third party class. Could any one give a technique to achieve this in cpp?

like image 349
user8153630 Avatar asked Jul 08 '17 04:07

user8153630


People also ask

How do I inherit from multiple classes?

Multiple Inheritance is a feature of C++ where a class can inherit from more than one classes. The constructors of inherited classes are called in the same order in which they are inherited. For example, in the following program, B's constructor is called before A's constructor.

Can a class inherit from multiple base classes?

You can derive a class from any number of base classes. Deriving a class from more than one direct base class is called multiple inheritance. The order of derivation is relevant only to determine the order of default initialization by constructors and cleanup by destructors.

How do I inherit multiple classes in Objective C?

There is no innate multiple inheritance (of course some see this as a benefit). To get around it you can create a compound class, i.e. a class with instance variables that are ids of other objects. Instances can specifically redirect messages to any combination of the objects they are compounded of.

Can a single class in Java inherit from more than one other class?

Therefore, in order to avoid such complications, Java does not support multiple inheritances of classes. Multiple inheritance is not supported by Java using classes, handling the complexity that causes due to multiple inheritances is very complex.


2 Answers

You cannot select inheritance at runtime, because the resulting type is always determined by the compiler at compile time.

What you can do is to apply the Strategy Pattern:

enter image description here

The idea is to have an abstract class that represents the algorithm used in MyNLP:

class Data;

class NLPAlgo {
public:
    virtual ~NLPAlgo() = default;
    virtual void Apply(Data&) = 0;
};

and provide concrete classes that use IPOPT and SQP:

class IPOPTAlgo : public NLPAlgo {
    IPOPT ipopt;
public:
    void Apply(Data& data) {
        // Use ipopt to realize the implementation
    }
}; 

class SQPAlgo : public NLPAlgo {
    SQP sqp;
public:
    void Apply(Data& data) {
        // Use sqp to realize the implementation
    }
}; 

Further take that abstract class as parameter for MyNLP

class MyNLP {
    std::unique_ptr<NLPAlgo> algo_;
public:
    MyNLP(std::unique_ptr<NLPAlgo> algo) : algo_(algo) {}
    void Apply(Data& data) {
        algo->Apply(data);
    }
};

Then you can configure at runtime which algorithm should be used with MyNLP:

// Note:
// That code could be factored out to an Abstract Factory:
// https://sourcemaking.com/design_patterns/abstract_factory
// That is figured out in more detail in this answer:
// https://stackoverflow.com/a/44985054/8242698
std::unique_ptr<NLPAlgo> algo;
if(condIPOPT) {
    algo = std::make_unique<IPOPTAlgo>();
}
else if(condSQP) {
    algo = std::make_unique<SQPAlgo>();
}

Data data;
MyNLP myNLP(algo);

myNLP.Apply(data);
like image 71
user0042 Avatar answered Oct 24 '22 12:10

user0042


With a little bit of template magic (well there is no such thing as magic in programming) I think this would help you to achieve your goal in the manner in which you were asking. There were many other great answers out there such Strategy Pattern, Factory, Dispatching etc. but this is a version that uses templates and inheritance from said library while choosing which one to instantiate at run time through the use of template specialization.

#include <iostream>

class A {
public:
    int a = 1;
    A() {}
};

class B {
public:
    float b = 2.0f;
    B() {}
};

class C {
public:
    char c = 'c';
    C() {}
};

template<class T>
class D : public T {
public:
    D() : T() {}
};


int main( int argc, char** argv ) {
    D<A> dA;
    D<B> dB;
    D<C> dC;

    std::cout << "D<A>::a = " << dA.a << "\n";
    std::cout << "D<B>::b = " << dB.b << "\n";
    std::cout << "D<C>::c = " << dC.c << "\n";

    std::cout << "Press any key and enter to quit." << std::endl;
    char c;
    std::cin >> c;

    return 0;
}

Here I have shown 3 different concrete or complete types classes A,B, & C that can represent your 3 different possible libraries that you would use to perform the evaluations or calculations to solve your problems. Class D is a template type that represents your MyNLP class. Now you can have MyNLP<A> mynlpA use the first library as your class will now inherit from it, and so on.

However; this is done at compile time and not runtime, and you have to instantiate the class with the specific types. You could use this template and set it up with user input through if statements or a switch statement within some defined function to choose which version of your class to create and use during runtime. Also notice that I specialized the different class template constructors based on the inheriting class's base class. Run this snippet to see how I was able to get the class template D<T> to inherit from A, B, or C based on user input at runtime.

#include <iostream>
#include <string>
#include <algorithm>

class A {
public:
    int a = 1;
    A() {}
};

class B {
public:
    float b = 2.0f;
    B() {}
};

class C {
public:
    char c = 'c';
    C() {}
};

template<class T>
class D : public T {
public:
    D() : T() {}
};

template<>
D<A>::D() {
    std::cout << "Initialize Library A\n";
}

template<>
D<B>::D(){
    std::cout << "Initialize Library B\n";
}

template<>
D<C>::D() {
    std::cout << "Initialize Library C\n";
}       

int main( int argc, char** argv ) {    
    std::string entry;
    std::cout << "Please choose which library to chose from: `A`, `B` or `C`\n";
    std::cout << "Or `Q` to quit\n";

    std::cin >> entry;

    std::transform(entry.begin(), entry.end(), entry.begin(), ::toupper);

    while ( true ) {

        if (entry == std::string("Q")) {
            break;
        }

        if (entry == std::string("A")) {
            D<A> dA;
            std::cout << "D<A>::a = " << dA.a << "\n";
        }

        if (entry == std::string("B")) {
            D<B> dB;
            std::cout << "D<B>::b = " << dB.b << "\n";

        }

        if (entry == std::string("C")) {
            D<C> dC;
            std::cout << "D<C>::c = " << dC.c << "\n";
        }

        entry.clear();
        std::cout << "Please choose which library to chose from: `A`, `B` or `C`\n";
        std::cout << "Or `Q` to quit\n";

        std::cin >> entry;

        std::transform(entry.begin(), entry.end(), entry.begin(), ::toupper);

    } 

    std::cout << "Press any key and enter to quit." << std::endl;
    char c;
    std::cin >> c;

    return 0;
}

There is a caveat to this method though: If the base class has private members/functions that you may need to call or use directly, they will be inaccessible to you, but the good thing is you will have access to anything that is public or protected, but this is the idea of data encapsulation.

like image 41
Francis Cugler Avatar answered Oct 24 '22 10:10

Francis Cugler