I learn C++ OOP-paradigm and want to ask related question:
Assumption
We have a base class:
class Base {
public:
virtual SomeType PowerMethod() { return SomeType{} };
}
We have a variable target and subclass which realizes some calculations with target variable based on the constructor's parameter (simple calculations or complicated calcs):
class Calc : public Base {
public: // using only public access to simplify real code structure
SomeType target;
void Simple() { target = 1; };
void Complex(){ target = 10000; };
explicit Calc(bool isSimple) {
if(isSimple)
Simple();
else
Complex();
}
};
Question
How to optimally realize two classes which based on different methods (Simple or Complex) but provide the same functionality of PowerMethod()?
My solution
class SimpleCalc : public Calc {
bool isSimple = true;
public:
SomeType PowerMethod() override {
Calc CalcInstance(isSimple);
return CalcInstance.target;
};
};
class ComplexCalc : public Calc {
bool isSimple = false;
public:
SomeType PowerMethod() override {
Calc CalcInstance(isSimple);
return CalcInstance.target;
};
};
This solution is pretty "ugly" and I want to ask you how to make it more readable.
Thank you!
I think that in your code, you didn't mean to craete a new Calc object, but instead call it on the superclass. This can be done like so:
Calc::Simple();
You can override the method PowerMethod, but still call the superclass's code:
virtual SomeType PowerMethod() override {
//do something
Base::PowerMethod();
}
If your problem is more complicated, and polymorphism and superclasses can't help you, you can always declare some method protected, so that only subclasses can access it. So, you could for example do this:
class Calc : public Base {
protected:
SomeType target;
void Simple() { target = 1; };
void Complex(){ target = 10000; };
public:
explicit Calc(bool isSimple) {
if(isSimple)
Simple();
else
Complex();
}
};
class SimpleCalc : public Calc {
public:
SomeType PowerMethod() override {
Calc::Simple();
return Calc::target;
};
};
class ComplexCalc : public Calc {
public:
SomeType PowerMethod() override {
Calc::Complex();
return Calc::target;
};
};
If your target is to learn OOP then you can use a factory design pattern to create your final calculator based on isSimple condition:
#include <iostream>
class Base
{
public:
Base()
{
target = 0;
}
int target;
virtual void PowerMethod() = 0;
};
class SimpleCalc : public Base
{
virtual void PowerMethod() { target = 0; }
};
class ComplexCalc : public Base
{
virtual void PowerMethod() { target = 1000; }
};
class CalcFactory
{
public:
virtual Base* createCalc(bool isSimple)
{
if (isSimple)
return new SimpleCalc();
else
return new ComplexCalc();
}
};
int main()
{
CalcFactory factory;
Base * base1 = factory.createCalc(true);
Base * base2 = factory.createCalc(false);
base1->PowerMethod();
base2->PowerMethod();
std::cout << base1->target << std::endl;
std::cout << base2->target << std::endl;
}
Related
This code demonstrates the problem:
class Base
{
public:
explicit Base(std::function<void()> const& printFunc) :
_printFunc(printFunc)
{
}
void print()
{
_printFunc();
}
private:
std::function<void()> _printFunc{};
private:
virtual void _print() = 0; // If this line is commented out, then
// `Subclass1::_print()` can be called.
};
class Subclass1 : public Base
{
public:
explicit Subclass1() :
Base([this]() { _print(); })
{
}
private:
void _print() /*override*/
{
std::cout << "Subclass1\n";
}
};
class Subclass2 : public Base, public Subclass1
{
public:
using fromLowestSubclass = Base;
public:
explicit Subclass2() :
Base([this]() { _print(); }), Subclass1()
{
}
private:
void _print() /*override*/
{
// Here is the problem:
Subclass1::print(); // or: static_cast<Subclass1*>(this)->print();
std::cout << "Subclass2\n";
}
};
int main()
{
Subclass2 sc2{};
sc2.fromLowestSubclass::print();
return 0;
}
In the Subclass2::_print method, the overriding _print method of Subclass1 should be called, but instead the Subclass1::print(); statement calls the current method again. This problem can be prevented if the statement virtual void _print() = 0; is commented out.
Why use of the virtual _print method prevents me from invoking the overloaded virtual method Subclass1::_print and what solution is there so that I do not have to do without virtual methods?
class Base
{
....
private:
virtual void _print() = 0;
}
This means: you can override _print, but you can't call it, only Base has right to call it.
Now:
class Base
{
public:
void print()
{
_printFunc();
}
does that, it calls _printFunc as a virtual function, which matches current object instantiation. It doesn't meter how print() was invoked.
Adding Subclass1:: as a prefix just changes name scope and doesn't have impact how method behaves. It has only have impact on name scope.
Now if virtual method has such prefix, then selecting name scope instruct compiler that you abandoning abstraction and you need to call specific method. In such case method is called without referring to a virtual table.
Double inheritance has no impact on this issue.
You can provide a helper method which you will be able to call from ancestor:
class Subclass1 : public Base
{
....
protected:
void sub1_print() // not virtual
{
std::cout << "Subclass1\n";
}
private:
void _print() /*override*/
{
sub1_print();
}
};
class Subclass2 : public Base, public Subclass1
{
....
private:
void _print() /*override*/
{
sub1_print();
std::cout << "Subclass2\n";
}
};
I am very new to c++ so I am trying to get a feeling of how to do things the right way in c++. I am having a class that uses one of two members. which one gets determined at instantiation. It looks something like
main() {
shared_pointer<A> a = make_shared<A>();
if ( checkSomething ) {
a->setB(make_shared<B>());
} else {
a->setC(make_shared<C>());
}
a->doStuff();
class A {
public:
doStuff() {
/*here I want to do something like call
m_b->doStuff() if this pointer is set and m_c->doStuff() if
that pointer is set.*/
}
setB( B* p ) { m_b = p; }
setC( C* p ) { m_c = p; }
B* m_b;
C* m_c;
}
}
B and C are some classes with doStuff() member function
There are many members like doStuff. Ideally I would avoid checking for nullptr in each of them. What is the best/most efficient/fastest way to create a switch between those two members?
Is there a way to use a static pointer so that I have a member
static **int m_switch;
and do something like
m_switch = condition ? &m_b : &m_c;
and call
*m_switch->doStuff();
Does the compiler here also replace the extra pointer hop because it is a static?
Is there any other smart way to do those switches?
Normally, class A would be an interface class, which both B and C would inherit and implement. But it sounds like you cannot do this for whatever reason.
Since you want to emulate this, you can start by making the interface:
class A_interface
{
public:
virtual void doStuff() = 0;
virtual void doThings() = 0;
virtual void doBeDoBeDo() = 0;
};
And then you make a template wrapper:
template< class T >
class A : public A_interface
{
public:
void doStuff() override { target.doStuff(); }
void doThings() override { target.doThings(); }
void doBeDoBeDo() override { target.doBeDoBeDo(); }
private:
T target;
};
This essentially does half of what your own example class A was trying to do, but now you can use a common interface. All you need to do is construct the correct templated version you want:
std::shared_ptr<A_interface> a;
if( checkSomething ) {
a = std::make_shared<A<B>>();
} else {
a = std::make_shared<A<C>>();
}
a->doStuff();
You need to have both members implement a common interface to use them similarly. But in order to do that, you need to define the interface and relay the calls to the B and C classes.
// existing classes
class B
{
public:
void doStuff() { std::cout << "B"; }
};
class C
{
public:
void doStuff() { std::cout << "C"; }
};
// define your interface
class I
{
public:
virtual void doStuff() = 0;
};
// new classes
class D : public B, public I
{
public:
void doStuff() override { B::doStuff(); }
};
class E : public C, public I
{
public:
void doStuff() override { C::doStuff(); }
};
// your A class
class A
{
public:
D* b = nullptr; // now type D
E* c = nullptr; // now type E
// your toggle
I* getActive()
{
if (b)
return b;
else
return c;
}
// simple doStuff() function
void doStuff()
{
getActive()->doStuff();
}
};
int main()
{
A a;
if (true)
a.b = new D; // need to initialize as D
else
a.c = new E; // need to initialize as E
a.doStuff(); // prints B
}
But typing this up made me realize that defining D and E could get really tiresome and against what you're trying to save. However, you can define a template to create them like #paddy has done.
There's no one-size-fits-all solution for your problem. What to use depends on your particular problem. A few possible answers:
Interfaces
Strategy Pattern
Pointers (to hold a function or class which implements doStuff)
An interface is like a contract. Any class which inherits from the interface must implement its members. For instance,
class IDoesStuff
{
public:
virtual ~IDoesStuff() {};
virtual void DoStuff() = 0;
};
Can now be used by other classes:
class Foo : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
class Bar : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
And now, in general, one may do:
Foo foo;
IDoesStuff *stuffDoer= &foo;
stuffDoer->doStuff();
This can be used in your particular use case as follows:
class A
{
IDoesStuff *stuffDoer; // Initialize this at some point.
public:
void doStuff() { stuffDoer->doStuff(); }
};
First you must change your memebr variables m_b and m_c to std::shared_ptr.
Add a member variable of type std::function(void()) to hold the target function you want to call. In your sample it is do_stuf.
In your setter functions you can bind target function to your std::function and in do_stuf just call std::function.
(You need a C++11 compiler)
class B
{
public:
void doStuff()
{
}
};
class C
{
public:
void doStuff()
{
}
};
class A
{
public:
void doStuff()
{
m_target_function();
}
void setB(std::shared_ptr<B> p)
{
m_b = p;
m_target_function = std::bind(&B::doStuff, m_b.get());
}
void setC(std::shared_ptr<C> p)
{
m_c = p;
m_target_function = std::bind(&C::doStuff, m_c.get());
}
std::shared_ptr<B> m_b;
std::shared_ptr<C> m_c;
std::function<void()> m_target_function;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<A> a = std::make_shared<A>();
bool use_B = false;
if (use_B)
{
a->setB(std::make_shared<B>());
}
else
{
a->setC(std::make_shared<C>());
}
a->doStuff();
}
In a nutshell, I want to use a single interface, IProducer, to create an object, IProduct. IProduct will have different components depending on which interface created it. The IProduct class will then be used by the IConsumer interface. The correct IConsumer class should be used (I do not want to do type checking myself) based on the derived type of IProduct.
I would essentially like to use the Strategy pattern (different behaviors behind a single interface), but with the added ability to return an object specific to the derived interface used. I want to abide by the Open/Close principle and not alter any of these existing classes when more functionality is added.
I would like to accomplish something like this (I'm sure the syntax is wrong somewhere but bear with me):
class IProduct {
public:
int intData;
};
class ProductA : public IProduct {
public:
float floatData;
};
class ProductB : public IProduct {
public:
bool boolData;
};
class IProducer {
public:
virtual IProduct* produce(void) = 0;
};
class ProducerA : public IProducer {
public:
IProduct* produce(void) {
return new ProductA;
}
};
class ProducerB : public IProducer {
public:
IProduct* produce(void) {
return new ProductB;
}
};
class IConsumer {
public:
virtual void consume(IProduct* prod) = 0;
};
class ConsumerA : public IConsumer {
public:
void consume(IProduct* prod) {
//I want to access the float!
}
};
class ConsumerB : public IConsumer {
public:
void consume(IProduct* prod) {
//I want to access the bool!
}
};
void main() {
IProducer* producer = ProducerFactory::create("ProducerA");
IProduct* product = producer->produce();
IConsumer* consumer = ConsumerFactory::create("ConsumerA");
consumer->consume(product); //I would like the correct consumer to be used here to deal with the ProductA class
}
If you think there is a better way to go about this I'm all ears. Thanks for your help!
What you need is a registry which maps IProduct implementations to the right IConsumer implementations. Basically its just an abstraction of a map:
class ConsumerRegistry
{
std::map<size_t, std::shared_ptr<IConsumer>> m_consumers;
public:
// we are not responsible for products, so lets allow plain ptrs here for more flexibility and less overhead
std::shared_ptr<IConsumer> GetConsumer(IProduct* product)
{
auto it = m_consumers.find(typeid(product).hash_code());
if (it == m_consumers.end())
return nullptr;
else
return it->second;
}
template<typename P>
void RegisterConsumer(std::shared_ptr<IConsumer> consumer)
{
m_consumers.emplace(typeid(P).hash_code(), consumer);
}
template<typename P>
void UnregisterConsumer()
{
m_consumers.erase(typeid(P).hash_code());
}
};
Either expose this class globally (e.g as singleton) or use it in the contexts where you need it. You register consumers like this:
reg.RegisterConsumer<ProductA>(new ConsumerA());
reg.RegisterConsumer<ProductB>(new ConsumerB());
We could also have a virtual void Register(ConsumerRegistry& reg) = 0; method inside IConsumer allowing for safer registering:
void ConsumerA::Register(ConsumerRegistry& reg, std::shared_ptr<IConsumer> self)
{
IConsumer::Register<ProductA>(reg, self);
}
// Required for friendship, can be static:
template<typename T>
void IConsumer::Register(ConsumerRegistry& reg, std::shared_ptr<IConsumer> self)
{
reg->RegisterConsumer<T>(self);
}
void ConsumberRegistry::RegisterConsumer(std::shared_ptr<IConsumer> consumer)
{
consumer->Register(*this, consumer);
}
Make both Register() and the low-level RegisterConsumer() methods private and let ConsumerRegistry and IConsumer be friends. Can be used like this then:
reg.RegisterConsumer(new ConsumerA());
reg.RegisterConsumer(new ConsumerB());
This is a solution I'm thinking of using. I'd appreciate any feedback.
I'm going to use the Visitor pattern and introduce the ProductVisitor class like so:
class IProductVisitor {
public:
explicit IProductVisitor() {}
virtual ~IProductVisitor(){}
virtual void visitA(ProductA* model) = 0;
virtual void visitB(ProductB* model) = 0;
};
class ProductTypeVisitor : public IProductVisitor {
public:
typedef enum {Unknown, A, B} ProductType;
explicit ProductTypeVisitor() : modelType(Unknown) {}
virtual ~ProductTypeVisitor(){}
virtual void visitA(ProductA* product) {
modelType = A;
}
virtual void visitB(ProductB* product) {
modelType = B;
}
ProductType getProductType(void) {
return modelType;
}
ProductType modelType;
};
class IProduct {
public:
IProduct() : intData(3) {}
virtual ~IProduct(){}
int intData;
virtual void accept(IProductVisitor* v) = 0;
};
class ProductA : public IProduct {
public:
ProductA() : IProduct(), floatData(5.5) { }
virtual ~ProductA(){}
float floatData;
void accept(IProductVisitor* v) {
v->visitA(this);
}
};
class ProductB : public IProduct {
public:
ProductB() : IProduct(),boolData(false) { }
virtual ~ProductB(){}
bool boolData;
void accept(IProductVisitor* v) {
v->visitB(this);
}
};
When making my factory, ConsumerFactor, I will use the ProductTypeVisitor class to determine what class the product is, dynamically cast it correctly (based off of the state of the enum), and then return a consumer initialized with the correct product.
class ConsumerFactory {
public:
explicit ConsumerFactory(void) {}
IConsumer* createFromProduct(IProduct* product) {
ProductTypeVisitor visitor;
product->accept(&visitor);
ProductTypeVisitor::ProductType productType = visitor.getProductType();
IConsumer* consumerPtr;
switch (productType) {
case ProductTypeVisitor::A :
consumerPtr = new ConsumerA(dynamic_cast<ProductA*>(product));
break;
case ProductTypeVisitor::B :
consumerPtr = new ConsumerB(dynamic_cast<ProductB*>(product));
break;
default:
std::cout << "Product type undefined. (throw exception)" << std::endl;
break;
}
return consumerPtr;
}
private:
ProductTypeVisitor visitor;
};
Finally, the code will look like this:
IProducer* producer = new ProducerA;
IProduct* product = producer->produce();
ConsumerFactory factory;
IConsumer* consumer = factory.createFromProduct(product);
consumer->consume();
Where the only thing that was ever specified, was ProducerA. Which, in my case, is the only thing that should be specified by the user. Also, I've isolated change areas to just two classes, the ConsumerFactory, and the IProductVisitor (which are very small changes to begin with).
If anyone could offer improvements or suggestions I'm all ears!
This is not the full solution (and maybe just a curiosity) but you can always do the tracking of types at compile time and use a bridging templated call to dispatch a product to the correct consumer.
#include <iostream>
template <class T>
class IProduct {
public:
virtual ~IProduct() {}
int intData;
typedef T consumer;
};
class ConsumerA;
class ProductA : public IProduct<ConsumerA> {
public:
float floatData;
};
class ConsumerB;
class ProductB : public IProduct<ConsumerB> {
public:
bool boolData;
};
template <class P, class C>
void apply(P* product, C* consumer) {
dynamic_cast<typename P::consumer*>(consumer)->consume(product);
}
template <class T>
class IConsumer {
public:
virtual void consume(IProduct<T>* prod) = 0;
};
class ConsumerA : public IConsumer<ConsumerA> {
public:
void consume(IProduct<ConsumerA>* prod) {
//I want to access the float!
std::cout << "ConsumerA" << std::endl;
std::cout << dynamic_cast<ProductA*>(prod)->floatData << std::endl;
}
};
class ConsumerB : public IConsumer<ConsumerB> {
public:
void consume(IProduct<ConsumerB>* prod) {
//I want to access the bool!
std::cout << "ConsumerB" << std::endl;
std::cout << dynamic_cast<ProductB*>(prod)->boolData << std::endl;
}
};
int main(int argc, char* argv[]) {
auto p_a = new ProductA;
auto c_a = new ConsumerA;
apply(p_a, c_a);
auto p_b = new ProductB;
auto c_b = new ConsumerB;
apply(p_b, c_b);
return 0;
}
I found this question while trying to solve a analogous issue. I ended up using std::any (which c++17 added to the language) to solve my problem. A single interface can return a std::any which you can cast back into the underlying type (via std::any_cast). In broad terms, std::any is like “hiding” types behind a void* pointer, but done in a type safe way, with full language and compiler support.
See:
std::any: How, when, and why
When should I use std::any
Related topic std::variant.
Sorry for the convoluted title of my question, conceptually it is quite simple but I can't find any good design to do it.
I have a base class accessible by the end user :
class A {
private:
// m is a functor
Base* m;
};
class Base {
public:
virtual void someInterface();
};
class DerivedT1 : public Base {
public:
virtual void someInterface()
{
some_parameter++;
}
private:
int some_parameter; // how to set?
};
class DerivedT2 : public Base {
public:
virtual void someInterface()
{
some_other_parameter += a_third_parameter;
}
private:
double some_other_parameter; // how to set?
double a_third_parameter; // how to set?
};
And I am trying to find the most generic way to set some_parameter and some_other_parameter from A's public interface.
I have thought of giving a number to my parameters but this sounds really ugly.
Is there any beautiful, object-oriented way to do this ?
you want to use A's public interface to set derived class parameters:
you can define a public function In A, which have a Base* parameter:
class A
{
public:
void setter(const Base *p);
{
m = p;
}
};
if you want to set Drived1 you can define a object of Derived1, can pass it to setter;
I think you want to pass value using A's public function, you must know the type of pointer of Base*,so you can pass value by the constructor of Derived1 or Derived2!
I nothing else works, you could always use a dynamic cast:
DerivedT1 *d1 = dynamic_cast<DerivedT1>(m);
if (d1 != nullptr)
{
// do something with derived 1
}
else
{
DerivedT2 *d2 = dynamic_cast<DerivedT2>(m);
if (d2 != nullptr)
{
// do something with derived 2
}
}
But if you need that, it's usually a sign that there is something wrong with your design.
If you want to do something along these lines
A a; a.setAlgorithmFamily(Algorithm::Type1);
a.getAlgorithmImplementation().setSomeParameter(34);
This is a quick and kind of dirty example of how you could do it. A::setAlgorithmType is basically a factory pattern in it's simplest form.
nclude <iostream>
using namespace std;
class Algorithm {
public:
virtual void setParameter(int value) = 0;
};
class AlgoX : public Algorithm {
int mX;
public:
void setParameter(int value) {
cout <<"Setting X to " <<value <<endl;
mX = value;
}
};
class AlgoY : public Algorithm {
int mY;
public:
void setParameter(int value) {
cout <<"Setting Y to " <<value <<endl;
mY = value;
}
};
class A {
public:
void setAlgorithmType(std::string type) {
cout <<"Now using algorithm " <<type <<endl;
if(type == "X")
mAlgorithm = new AlgoX();
else if(type == "Y")
mAlgorithm = new AlgoY();
}
Algorithm* getAlgorithmImplementation() { return mAlgorithm; }
private:
Algorithm* mAlgorithm;
};
int main(int argc, char** argv) {
A a;
a.setAlgorithmType("X");
a.getAlgorithmImplementation()->setParameter(5);
return 0;
}
This gives:
Now using algorithm X
Setting X to 5
My problem is the following:
int main()
{
Base* derivedobject = new Derived1();
derivedobject->GetProperties()-> ???
return 0;
}
//********************
// BaseClass.h
//********************
struct PropertyStruct
{
int x;
};
class Base
{
public:
Base();
~Base();
virtual PropertyStruct GetProperties() = 0;
private:
};
//********************
// DerivedClass1.h
//********************
struct PropertyStruct
{
int y;
};
class Derived1 : public Base
{
public:
Derived1();
~Derived1();
PropertyStruct GetProperties() { return myOwnDifferentProperties; };
private:
};
//********************
// DerivedClass2.h
//********************
struct PropertyStruct
{
float z;
};
class Derived2 : public Base
{
public:
Derived2();
~Derived2();
PropertyStruct GetProperties() { return myOwnDifferentProperties };
private:
};
If I do it like that I'm going to get an error saying that PropertyStruct is a redefinition. If I use a namespace or rename the struct inside the derived class I am then going to get an error telling me that the return type is not the same as defined by Base.
If I define the virtual functions return type as a pointer it compiles, though the next problem when accessing the function "GetProperties" from the main method (in this example) the base object does not know what variables are inside the struct of the derived class.
Is there any way I can realize this ?
That I can get the different properties of each derived object but using the base class object ?
As others have mentioned, there are ways to achieve your goals here but ultimately you will find yourself writing code like the following:
Base * object = ...;
if object is Derived1 then
get Property1 and do something with it
else if object is Derived2 then
get Property2 and do something with it
This is an anti-pattern in object-oriented programming. You already have a class hierarchy to represent the differences between the various derived types. Rather than extracting the data from your objects and processing it externally, consider adding a virtual function to the base class and letting the derived classes do the processing.
class Base
{
public:
virtual void DoSomething() = 0;
};
class Derived1 : Base
{
public:
void DoSomething()
{
// use myOwnDifferentProperties as necessary
}
private:
PropertyStruct myOwnDifferentProperties;
};
If it's not appropriate to put the required processing in the derived classes (i.e. if it would introduce unwanted responsibilities) then you may want to consider the Visitor Pattern as a way to extend the functionality of your hierarchy.
Since template functions cannot be virtual you can use hierarchy of your properties. It's only one way, no other ways. For get elements of derived Properties you should use virtual getter functions.
struct BaseProp
{
virtual ~BaseProp() { }
virtual boost::any getProperty() const = 0;
};
struct PropertyStruct : BaseProp
{
boost::any getProperty() const { return x; }
private:
int x;
};
struct PropertyStruct2 : BaseProp
{
boost::any getProperty() const { return y; }
private:
float y;
};
class Base
{
public:
virtual std::shared_ptr<BaseProp> GetProperties() const = 0;
virtual ~Base() { }
}
class Derived
{
public:
std::shared_ptr<BaseProp> GetProperties() const { return new PropertyStruct(); }
};
class Derived2
{
public:
std::shared_ptr<BaseProp> GetProperties() const { return new PropertyStruct2(); }
};
You can use template class to do that:
struct PropertyStruct1 {
float f;
};
struct PropertyStruct2 {
int i;
};
template<class T>
class A{
public:
T GetProperties() {return mProps;}
private:
T mProps;
};
int main (int argc, const char * argv[]) {
A<PropertyStruct1> a1;
int f = a1.GetProperties().f;
A<PropertyStruct2> a2;
int i = a2.GetProperties().i;
return 0;
}