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?
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.
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.
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.
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.
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:
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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With