Singleton pattern in C++ for a DI container - c++

I am trying to create a DI container in C++ (for studying purposes). I know about boost DI container option, but I just want to have fun writing one by myself.
I would like that the created container only had one instance per object "registered", so I should apply the Singleton design pattern.
But, what would be the best (idiomatic) way to implement the Singleton Pattern as an in C++20 or, at least, in modern C++ and why?

Do you mean something like this, using meyer's singleton.
(https://www.modernescpp.com/index.php/thread-safe-initialization-of-a-singleton)
I never use singletons that need to be created with new, since their destructor never gets called. With this pattern the destructors do get called when the program terminates.
#include <iostream>
//-----------------------------------------------------------------------------
// create an abstract baseclass (closest thing C++ has to an interface)
struct data_itf
{
virtual int get_value1() const = 0;
virtual ~data_itf() = default;
protected:
data_itf() = default;
};
//-----------------------------------------------------------------------------
// two injectable instance types
struct test_data_container :
public data_itf
{
int get_value1() const override
{
return 0;
}
~test_data_container()
{
std::cout << "test_data_container deleted";
}
};
struct production_data_container :
public data_itf
{
int get_value1() const override
{
return 42;
}
~production_data_container()
{
std::cout << "production_data_container deleted";
}
};
//-----------------------------------------------------------------------------
// meyers threadsafe singleton to get to instances implementing
// interface to be injected.
//
data_itf& get_test_data()
{
static test_data_container test_data;
return test_data;
}
data_itf& get_production_data()
{
static production_data_container production_data;
return production_data;
}
//-----------------------------------------------------------------------------
// object that needs data
class my_object_t
{
public:
explicit my_object_t(const data_itf& data) :
m_data{ data }
{
}
~my_object_t()
{
std::cout << "my_object deleted";
}
void function()
{
std::cout << m_data.get_value1() << "\n";
}
private:
const data_itf& m_data;
};
//-----------------------------------------------------------------------------
int main()
{
auto& data = get_production_data();
my_object_t object{ data };
object.function();
return 0;
}

Related

How to use polymorphism to execute command on objects, which have no common base class?

I am receiveing commands through json, which I insert in to a pipe. For this reason thye must have the same base class.
The pipe is read by a pipe handler, some commands are consumed by the pipe handler, others have to be passed down to a device, which is a member of the pipe handler. I could simply do this:
class Command{};
class HandlerCommand : public Command {
void execute(Handler* h);
};
class DeviceCommand : public Command {
void execute(Device* d);
};
Command* c = pipe.receive();
if (const auto hc = dynamic_cast<const HandlerCommand*>(c)) { hc.execute( **handlerptr** ); }
else if (const auto dc = dynamic_cast<const DeviceCommand*>(c)) { dc.execute( **deviceptr** );}
Device and pipehandler should not have the same base, since they have no common methods, fields, they are conceptually different.
Is there a way to avoid using dynamic cast here. I was thinking maybe there is some neat design pattern for this, but couldn`t quit come up with a better solution.
EDIT: did not derive DeviceCommand and HandlerCommand from command, fixed this.
You cannot use polymorphism of two things which have nothing in common. You will need the same base class/interface: in your case Command. As mentioned above your base class requires a pure virtual function that must be implemented by the derived classes. I will utilize a Command * clone()const prototype, which could be very useful later on. Please introduce a virtual destructor of your base class, otherwise, to track down this memory error could be a pain in the ass. Note, regarding your dynamic_cast the member function execute, must be const. You may try this:
#include <iostream>
#include <vector>
class Handler
{
public:
Handler(){}
};
class Device
{
public:
Device(){}
};
enum class CommandType{Handler,Devise};
class Command
{
public:
virtual ~Command(){}
virtual Command*clone()const = 0;
virtual CommandType getType()const = 0;
};
class HandlerCommand : public Command {
public:
HandlerCommand():Command(){}
void execute(Handler* h) const
{
std::cout << __FUNCTION__<<"\n";
}
HandlerCommand*clone()const { return new HandlerCommand(*this); }
CommandType getType()const { return CommandType::Handler; }
};
class DeviceCommand : public Command{
public:
DeviceCommand():Command(){}
void execute(Device* d)const
{
std::cout << __FUNCTION__<<"\n";
}
DeviceCommand*clone()const { return new DeviceCommand(*this); }
CommandType getType()const { return CommandType::Devise; }
};
int main()
{
Device dev;
Handler handler;
std::vector<Command*> pipe{ new HandlerCommand(), new DeviceCommand() };
while (!pipe.empty())
{
Command* c = pipe.back();
if (c->getType() == CommandType::Handler) { static_cast<const HandlerCommand*>(c)->execute(&handler); }
else if (c->getType() == CommandType::Devise ) { static_cast<const DeviceCommand*>(c)->execute(&dev); }
delete c;
pipe.pop_back();
}
std::cin.get();
}
outputs:
DeviceCommand::execute
HandlerCommand::execute
Version 2.0 using std::variant. You will need at least C++17 to compile this. Note, a single pipe container can exclusively comprise one of the mentioned classes within the variant. So there is no casting anymore, but you will need two pipes. Because of that, I introduced a time stamp variable.
#include <iostream>
#include <vector>
#include <variant>
class Handler
{
public:
Handler() {}
};
class Device
{
public:
Device() {}
};
class HandlerCommand {
int ts;
public:
HandlerCommand(int _ts):ts(_ts) {}
void execute(Handler* h) const
{
std::cout << ts << ": "<< __FUNCTION__ << "\n";
}
int timeStamp()const { return ts; }
};
class DeviceCommand {
int ts;
public:
DeviceCommand(int _ts) :ts(_ts) {}
void execute(Device* d)const
{
std::cout << ts << ": " << __FUNCTION__ << "\n";
}
int timeStamp()const { return ts; }
};
using Command = std::variant<HandlerCommand, DeviceCommand>;
int main()
{
Device dev;
Handler handler;
std::vector<Command> hcPipe{HandlerCommand(2),HandlerCommand(5)};
std::vector<Command> dcPipe{DeviceCommand(1),DeviceCommand(4)};
Command single = DeviceCommand(0);
if (single.index() == 0)
{
std::get<HandlerCommand>(single).execute(&handler);
}
else
{
std::get<DeviceCommand>(single).execute(&dev);
}
while (!hcPipe.empty() || !dcPipe.empty())
{
if (!hcPipe.empty() && (dcPipe.empty() || std::get<HandlerCommand>(hcPipe.front()).timeStamp() < std::get<DeviceCommand>(dcPipe.front()).timeStamp()))
{
std::get<HandlerCommand>(hcPipe.front()).execute(&handler);
hcPipe.erase(hcPipe.begin());
}
else
{
std::get<DeviceCommand>(dcPipe.front()).execute(&dev);
dcPipe.erase(dcPipe.begin());
}
}
std::cin.get();
}
outputs:
0: DeviceCommand::execute
1: DeviceCommand::execute
2: HandlerCommand::execute
4: DeviceCommand::execute
5: HandlerCommand::execute

C++ declare derived class object inside of if-else and use it outside

I have a (parent) class named Alma with the (virtual) function Getwidth() and two derived class of Alma, named Birs (with the special function Getheight()) and Citrom (with the special function Getdepth()). I want to declare an object - named Attila - which type is Birs or Citrom depending on a bool. Later, I want to use the common function Getwidth() and also the special functions (depending the bool mentioned).
My (not working) code:
/*...*/
/*Classes*/
class Alma{
public: virtual int Getwidth() = 0;
/*ect...*/
}
class Birs: public Alma{
int Getwidth(){return 1;}
public: int Getheight(){return 2;}
/*ect...*/
}
class Citrom: public Alma{
int Getwidth(){return 3;}
public: int Getdepth(){return 4;}
/*ect...*/
}
/*...*/
/*Using them*/
void Useobjects(){
/*Create object depending on bool*/
if(b00lvar){
Birs Andor();
std::cout<<Andor.Getwidth()<<" "<<Andor.Getheight()<<std::endl;
}else{
Citrom Andor();
std::cout<<Andor.Getwidth()<<" "<<Andor.Getdepth()<<std::endl;
}
/*Using the common part of object*/
std::cout<<Andor.Getwidth()<<std::endl;
/*Using the special part of object*/
if(b00lvar){
std::cout<<Andor.Getheight()<<std::endl;
}else{
std::cout<<Andor.Getdepth()<<std::endl;
}
/*ect...*/
}
This is a classic case of polymorphic object handling. Just make sure you are familiar with that concept as well with pointers and references.
What you need is something looking like:
Alma* Andor;
if(b00lvar){
Andor = new Birs();
std::cout<<Andor->Getwidth()<<" "<<Andor->Getheight()<<std::endl;
}else{
Andor = new Citrom();
std::cout<<Andor->Getwidth()<<" "<<Andor->Getdepth()<<std::endl;
}
Next use dynamic_cast to get back to the derived types and finally of course do not forget to delete the object. But first read about those concepts.
You cannot define a single object whose type is this or that, depending on something else. C++ doesn't work this way. C++ is a statically-typed language. This means that the type of every object is determined at compile time. Other languages, like Perl, or Javascript, are dynamically-typed, where the type of an object is determined at runtime, and a single object can be one thing, at one point, and something else at a different point.
But C++ does not work this way.
To do something like what you're trying to do, you have to refactor the code, and work with the virtual superclass. Something like this:
void UseObject(Alma &andor)
{
/*Using the common part of object*/
std::cout<<andor.Getwidth()<<std::endl;
/*Using the special part of object*/
/* This part is your homework assignment */
}
void Useobjects(){
/*Create object depending on bool*/
if(b00lvar){
Birs andor;
std::cout<<Andor.Getwidth()<<" "<<Andor.Getheight()<<std::endl;
UseObject(andor);
}else{
Citrom andor;
std::cout<<Andor.Getwidth()<<" "<<Andor.Getdepth()<<std::endl;
UseObject(andor);
}
}
Another approach would be to use two pointers, in this case passing two pointers to UseObject(). One of the two pointers will always be a nullptr, and the other one a pointer to the instantiated object, with UseObject() coded to deal with whatever object is passed in.
That's also possible, but will result in ugly code, and if I was an instructor teaching C++, I would mark down anyone who handed in code that did that.
If the type of the object (Alma or Citrom) is decided at the startup, then it's a classic polymorphism, as other answers described:
https://stackoverflow.com/a/36218884/185881
What're you missing from your design is, to name the common ancestor with common behaviors (e.g. Gyumolcs).
If the object should once act as Alma and other times as Citrom, you should implement a single class, which have a flag or enum (ACT_AS_CITROM, ACT_AS_ALMA), or, if the behavior is limited to one method, then it should have a parameter, which tells which action to perform (alma-like or citrom-like).
You can do this with pointer semantic and type introspection with dynamic_cast. I extended your example to show how I would approach it.
Here is the Demo
#include <iostream>
#include <memory>
using namespace std;
class Alma{
public:
virtual int Getwidth() = 0;
};
class Birs: public Alma{
public:
int Getwidth() { return 1; }
int Getheight() { return 2; }
};
class Citrom: public Alma{
public:
int Getwidth() { return 3; }
int Getdepth() { return 4; }
};
shared_ptr<Alma> make_attila(bool birs)
{
if (birs)
return make_shared<Birs>();
else
return make_shared<Citrom>();
}
void test_attila(shared_ptr<Alma> attila)
{
cout << "width: " << attila->Getwidth() << "\n";
if (auto as_birs = dynamic_pointer_cast<Birs>(attila))
cout << "height: " << as_birs->Getheight() << "\n";
else if (auto as_citrom = dynamic_pointer_cast<Citrom>(attila))
cout << "depth: " << as_citrom->Getdepth() << "\n";
}
int main() {
shared_ptr<Alma> attila = make_attila(true);
test_attila(attila);
attila = make_attila(false);
test_attila(attila);
return 0;
}
Next step would be to make make_attila a template function taking the Derived class as a template parameter instead of a bool.
template <class Derived>
shared_ptr<Alma> make_attila()
{
return make_shared<Derived>();
}
Two things:
If you want to use it outside the if, you will have to declare it outside the if.
You need references or pointers for this kind of polymorphism.
unique_ptr<Alma> Andor;
if (b00lvar) {
Andor = make_unique<Birs>();
} else {
Andor = make_unique<Citrom>();
}
std::cout << Andor->Getwidth() << std::endl;
Some other answer suggested using shared_ptr but that's overkill here. 99% of the time unique_ptr is sufficient.
Polymorphism isn't always the way to go if an object is known to be either a B or a C. In this case, a boost::variant is often more succinct.
Having said this, if you want to go down the polymorphic route it's important to remember something that will guide the design.
Polymorphic means runtime polymorphic. I.e. the program cannot know the real type of the object. It also cannot know the full set of possible types the object could be, since another developer could manufacture a type that your module's code knows nothing about. Furthermore, when using the Alma interface, the code should not need to know anything more. Invoking magic such as "I know it'll be a Citrom because the bool is true" is laying the foundations for a code maintenance nightmare a few weeks or months down the line. When done in commercial, production code, it results in expensive and embarrassing bug-hunts. Don't do that.
This argues that all relevant information about any object of type Alma must be available in the Alma interface.
In our case, the relevant information is whether it has the concept of height and/or depth.
In this case, we should probably include these properties in the base interface plus provide functions so that the program can query whether the property is valid before using it.
Here is something like your example written this way:
#include <iostream>
#include <memory>
#include <typeinfo>
#include <string>
#include <exception>
#include <stdexcept>
// separating out these optional properties will help me to reduce clutter in Alma
struct HeightProperty
{
bool hasHeight() const { return impl_hasHeight(); }
int getHeight() const { return impl_getHeight(); }
private:
// provide default implementations
virtual bool impl_hasHeight() const { return false; }
virtual int impl_getHeight() const { throw std::logic_error("getHeight not implemented for this object"); }
};
struct DepthProperty
{
bool hasDepth() const { return impl_hasDepth(); }
int getDepth() const { return impl_getDepth(); }
private:
virtual bool impl_hasDepth() const { return false; }
virtual int impl_getDepth() const { throw std::logic_error("getDepth not implemented for this object"); }
};
class Alma : public HeightProperty, public DepthProperty
{
public:
Alma() = default;
virtual ~Alma() = default;
// note: nonvirtual interface defers to private virtual implementation
// this is industry best practice
int getWidth() const { return impl_getWidth(); }
const std::string& type() const {
return impl_getType();
}
private:
virtual int impl_getWidth() const = 0;
virtual const std::string& impl_getType() const = 0;
};
class Birs: public Alma
{
private:
// implement the mandatory interface
int impl_getWidth() const override { return 1; }
const std::string& impl_getType() const override {
static const std::string type("Birs");
return type;
}
// implement the HeightProperty optional interface
bool impl_hasHeight() const override { return true; }
int impl_getHeight() const override { return 2; }
};
class Citrom: public Alma
{
private:
// implement the mandatory interface
int impl_getWidth() const override { return 3; }
const std::string& impl_getType() const override {
static const std::string type("Citrom");
return type;
}
// implement the DepthProperty optional interface
bool impl_hasDepth() const override { return true; }
int impl_getDepth() const override { return 4; }
};
/*...*/
/*Using them*/
// generate either a Birs or a Citrom, but return the Alma interface
std::unique_ptr<Alma> make_alma(bool borc)
{
if (borc) {
return std::make_unique<Birs>();
}
else {
return std::make_unique<Citrom>();
}
}
void Useobjects()
{
for (bool b : { true, false })
{
std::unique_ptr<Alma> pa = make_alma(b);
std::cout << "this object's typeid name is " << pa->type() << std::endl;
std::cout << "it's width is : " << pa->getWidth() << std::endl;
if(pa->hasHeight()) {
std::cout << "it's height is: " << pa->getHeight() << std::endl;
}
if(pa->hasDepth()) {
std::cout << "it's depth is: " << pa->getDepth() << std::endl;
}
}
}
int main()
{
Useobjects();
return 0;
}
expected output:
this object's typeid name is Birs
it's width is : 1
it's height is: 2
this object's typeid name is Citrom
it's width is : 3
it's depth is: 4

Accessing variables shared between classes within an aggregator class

I have a problem in hand which requires to make a very modular design for different algorithms. For example population based optimization algorithms like genetic algorithm, particle swarm algorithm etc. There are several variants of these algorithms, therefore I planned to make the smaller building blocks as an abstract class and let the specific building block to be plugged in.
For example lets say we have algo1 which can be divided in the following subroutines
algo1
loop
{
sub1 ()
sub2 ()
sub3 ()
}
For this I can create three interfaces which the implementation will override as per their implementation. Therefore
//Sub1Class, Sub2Class, Sub3Class are interfaces/abstract classes
class algo1
{
sub1Class *sub1Obj;
sub2Class *sub2Obj;
sub3Class *sub3Obj;
}
// constructor or setter method to set the implementation
algo1 (Sub1Class *myAlgo1Obj, Sub2Class myAlgo1Obj, Sub3Class myAlgo1Obj)
{
sub1Obj = myAlgo1Obj;
sub2Obj = myAlgo2Obj;
sub3Obj = myAlgo3Obj;
}
doAlgo1
{
loop
{
sub1Obj->algo ();
sub2Obj->algo ();
sub3Obj->algo ();
}
}
This can be done, but all the algorithms uses the attributes of the algo class and there are intermediate variables shared by the algorithms which I do not want to give a getter/setter.
My question is what are the techniques which can be used to manage the shared intermediate variables between the algorithms. I can pass it as the algo method implementation argument, but the number of intermediates and the types may change from one implementation to another. In that case will it be a good idea to create a separate class of temporary variable or make something like friend in cpp? Note that the intermediate results can be large vectors and matrices.
Please let me know if you need more information or clarification.
NOTE: I can possibly omit the variables shared between the algorithms by introducing locals and re-computation, but the algorithms are iterative and computation intensive involving large matrices therefore I want to make object creation and destruction as minimum as possible.
I can propose to use Inverse of Control container to solve your problem.
First you should create several abstract classes to keep it in the container:
class ISubroutineState {
public:
ISubroutineState() = default;
virtual int getVar1() const = 0;
virtual void setVar1(int v1) = 0;
};
class ISubroutineState1 : public ISubroutineState {
public:
virtual std::string getVar2() const = 0;
virtual void setVar2(std::string& v2) = 0;
};
The example of the subroutine state class implementation:
class SubState1 : public ISubroutineState1 {
int var1;
std::string var2;
public:
int getVar1() const {
return var1;
}
std::string getVar2() const {
return var2;
}
void setVar1(int v1) { var1 = v1; }
void setVar2(std::string& v) { var2 = v; }
};
The the IoC container (please note it can be accessed in any way allowed - i used just static pointer for simplicity):
class StateBroker
{
std::map<const char*, ISubroutineState*> *storage;
public:
StateBroker();
template <class S>
void StateBroker::bind(S* state) {
storage->emplace(typeid(S).name(), state);
}
template <class S>
S* StateBroker::get() const {
auto found = storage->find(typeid(S).name());
if (found == storage->end()) return NULL;
return (S*)found->second;
}
~StateBroker();
};
StateBroker* stateBroker;
Now you can implement any type of the subroutines:
class ISubroutine {
public:
virtual void Execute() = 0;
};
class Sub1Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub1 called" << std::endl;
}
else {
ISubroutineState1* ss1 = stateBroker->get<ISubroutineState1>();
std::cout << "Sub1 with state called" << std::endl;
ss1->setVar1(1);
ss1->setVar2(std::string("State is changed by Sub1Class"));
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
class Sub2Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub2 called" << std::endl;
}
else {
ISubroutineState* ss1 = stateBroker->get<ISubroutineState>();
std::cout << "Sub2 with state called" << std::endl;
ss1->setVar1(2);
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
class Sub3Class : public ISubroutine {
public:
void Execute()
{
if (stateBroker == NULL)
{
std::cout << "Sub3 called" << std::endl;
}
else {
ISubroutineState1* ss1 = stateBroker->get<ISubroutineState1>();
std::cout << "Sub3 with state called" << std::endl;
ss1->setVar1(3);
ss1->setVar2(std::string("State is changed by Sub3Class"));
std::cout << *static_cast<SubState1*>(ss1) << std::endl;
}
}
};
Also please note that subroutine' Execute() can request any type of subroutine state it requires to perform their tasks. It can even create additional state instances (to use in later stage of the algorithm, for example).
Now the main algorithm would look like this:
class Algo {
private:
Sub1Class* sub1;
Sub2Class* sub2;
Sub3Class* sub3;
public:
Algo(Sub1Class* s1, Sub2Class* s2, Sub3Class* s3) : sub1(s1), sub2(s2), sub3(s3){}
void Execute()
{
sub1->Execute();
sub2->Execute();
sub3->Execute();
}
};
... and it's usage (please note it can be used as stateless and as statefull depending on the fact the StateBroker is initialized or not)
Sub1Class s1;
Sub2Class s2;
Sub3Class s3;
std::cout << "Stateless algorithm" << std::endl;
Algo mainAlgo(&s1, &s2, &s3);
mainAlgo.Execute();
stateBroker = new StateBroker();
SubState1* state = new SubState1();
stateBroker->bind<ISubroutineState>(state);
stateBroker->bind<ISubroutineState1>(state);
std::cout << "Statefull algorithm" << std::endl;
Algo statefulAlgo(&s1, &s2, &s3);
statefulAlgo.Execute();
Please note that Algo class doesn't know anything about subroutine states, state broker, etc.; Sub2Class doesn't know about ISubroutineState1; and StateBroker doesn't care about state and subroutine implementation.
BTW, you can review the example project at https://github.com/ohnefuenfter/cppRestudy (VS2015)

Composite with smart pointers without dynamic_pointer_cast

I implemented the composite pattern using smart pointers, it works until a point.
The problem is that I just can use the methods that is implemented in the interface and I can not use the methods that is defined in the derived class without using dynamic_pointer_cast and I don't want it.
I want to know if it's possible to do it without using dynamic_pointer_cast.
I heard that I need to implement the visitor pattern, but I really don't know how to and if it fits in that problem.
#include <iostream>
#include <vector>
#include <memory>
class Fruit
{
public:
virtual void getOld() = 0;
};
class Orange : Fruit
{
public:
Orange() {}
void add(std::shared_ptr<Fruit> f)
{
v.push_back(f);
}
std::shared_ptr<Fruit> get(int k)
{
return v[k];
}
void getOld()
{
std::cout << "Orange - I'm old." << std::endl;
}
private:
std::vector<std::shared_ptr<Fruit>> v;
};
class Bitter : public Fruit
{
public:
Bitter() {}
void getOld()
{
std::cout << "Bitter - I'm old." << std::endl;
}
void getNew()
{
std::cout << "Bitter - I'm new." << std::endl;
}
};
int main(int argc, char ** argv)
{
auto orange = new Orange;
orange->add(std::make_shared<Bitter>());
auto bitter = orange->get(0);
bitter->getOld();
return 0;
}
It works as you can see here on the live preview, but when I try to use:
int main(int argc, char ** argv)
{
auto orange = new Orange;
orange->add(std::make_shared<Bitter>());
auto bitter = orange->get(0);
bitter->getOld();
bitter->getNew();
return 0;
}
I got errors:
error: 'class Fruit' has no member named 'getNew'
Thanks in advance.
The problem here I think is that it would work with polymorphism but the method 'getNew' doesn't exist in the mother class so you need to define it and make it virtual. It's the only way to do it without using a cast on the object.
With this line it should work.
virtual void getNew() = 0;
One possible solution is to have the following function in Orange.
template <typename T>
T* get(int k)
{
return dynamic_cast<T*>(v[k].get());
}
And then use:
auto bitter = orange->get<Bitter>(0);
bitter->getOld();
bitter->getNew();
This performs a dynamic_cast but is localized to Orange.
Following information can be found about "composite pattern" from the GOF book. Of course it has been explained based on graphics class.
The key to the Composite pattern is an abstract class that represents both primitives and their containers. For the graphics system, this class is Graphic. Graphic declares operations like Draw that are specific to graphical objects. It also declares operations that all composite objects share, such as operations for accessing and managing its children.
Based on the above explanation,we should ideally declare all possible interfaces of leaf and non-leaf(container) type of node while using composite pattern.I think that this is essential in order to let client treating individual objects and compositions of objects uniformly. So ideally you should declare your classes in the following way while using this particular pattern. Any logic which has been written based on the exact type of object in the client code violates the essence of this pattern.
//Abstract class which should have all the interface common to
// Composite and Leaf class. It may also provide the default
// implementation wherever appropriate.
class Fruit {
public:
virtual void getOld() = 0;
virtual void getNew() = 0;
virtual void add(std::shared_ptr<Fruit> f) { }
virtual std::shared_ptr<Fruit> get(int index ) {return nullptr; }
virtual ~Fruit() { }
};
//Composite Node
class Orange : Fruit {
public:
Orange() {}
void add(std::shared_ptr<Fruit> f) { v.push_back(f); }
std::shared_ptr<Fruit> get(int k) { return v[k]; }
void getOld() { std::cout << "Orange - I'm old." << std::endl; }
void getNew() { std::cout << "Orange - I'm new." << std::endl; }
private:
std::vector<std::shared_ptr<Fruit>> v;
};
//Leaf node
class Bitter : public Fruit {
public:
Bitter() {}
void getOld() { std::cout << "Bitter - I'm old." << std::endl; }
void getNew() { std::cout << "Bitter - I'm new." << std::endl; }
};

Designing Delayed Loading

I am having a hard time figuring how to design classes that can't initialize all their internal members in the constructor. I know that this should be something basic and discussed all over the net, but I'm not sure what to look for. So, for example, please consider the following code:
#include <iostream>
class Workhorse
{
public:
void SetData (const int &data)
{
this->data = data;
}
int GetData () const
{
return this->data;
}
private:
int data;
};
class Worker
{
public:
Worker ()
{
}
void Initialize (const int &data)
{
horse.SetData(data);
}
void Action () const
{
std::cout << horse.GetData() << std::endl;
}
private:
Workhorse horse;
};
int main ()
{
Worker worker;
worker.Initialize(3);
worker.Action();
return 0;
}
I want to prevent the workers from calling any methods without first calling Initialize(). The layman's implementation would be to add an isInitialized flag in the Worker class, set it to true in Initialize() and test it at the beginning of each public method (maybe also in the protected / private ones, if we introduce some inheritance?). Unfortunately, this seems a bit cumbersome and hard to maintain. Also, it's just awful to repeat an if statement in all methods. I haven't even began to ponder about thread safety issues, but, right now, I'm only implementing a single-threaded application. Is there a smarter way to design this?
EDIT: OK, I chose a dumb design as an example, which, indeed, is flawed. Let me try to give a clearer picture of what I have:
#include <iostream>
class PublicKeyCryptoProvider
{
public:
struct PublicKey
{
int shared;
};
struct PrivateKey
{
int secret;
};
int Encrypt (const int &plaintext) const
{
int ciphertext;
//apply encryption algorithm on plaintext
ciphertext = plaintext * this->pk.shared;
return ciphertext;
}
int Decrypt (const int &ciphertext) const
{
int plaintext;
//apply decryption algorithm on ciphertext
plaintext = ciphertext / this->sk.secret;
return plaintext;
}
void GenerateKeys ()
{
this->pk.shared = 4;
this->sk.secret = 4;
//generate pk and sk
}
void SetPublicKey (const PublicKey &pk)
{
this->pk = pk;
}
const PublicKey &GetPublicKey () const
{
return this->pk;
}
private:
PublicKey pk;
PrivateKey sk;
};
int main ()
{
/* scenario 1: */
PublicKeyCryptoProvider cryptoProvider;
cryptoProvider.GenerateKeys();
std::cout << cryptoProvider.Decrypt(cryptoProvider.Encrypt(3)) << std::endl;
/* /scenario 1: */
/* scenario 2: */
PublicKeyCryptoProvider cryptoProvider1;
cryptoProvider1.GenerateKeys();
PublicKeyCryptoProvider cryptoProvider2;
cryptoProvider2.SetPublicKey(cryptoProvider1.GetPublicKey());
int ciphertext = cryptoProvider2.Encrypt(3);
std::cout << cryptoProvider1.Decrypt(ciphertext) << std::endl;
//now let's do something bad...
std::cout << cryptoProvider2.Decrypt(ciphertext) << std::endl;
/* /scenario 2: */
return 0;
}
Obviously, you can imagine real life examples where scenario 2 is perfectly valid. Given the above situation, is there any better option than adding a canDecrypt flag inside the PublicKeyCryptoProvider class, which is set to true when generating keys and then tested at the beginning of the decrypt method? I have to mention that this is a very simple example, because, in my case, the PublicKeyCryptoProvider can perform faster encryptions if it is the owner of the secret key and it has much more public methods, so I would be doomed to test the flag more than a couple of times... Also, I have a client - server mockup scenario where the server exposes a bunch of public methods for the client, but the client can only call the methods after it has called the Initialize() method on the server...
I would do the following :
class Worker
{
public:
Worker (const int& data)
{
horse.SetData(data);
}
void Action () const
{
std::cout << horse.GetData() << std::endl;
}
private:
Workhorse horse;
};
Since you obviously don't want a Worker object to exist without being initialized, its initialization should be a part of its construction, and it should be instanciated without this initialization since it can't work without it.
It sounds like the behaviour you're interested in would entail having a class that acts as a manager, deciding whether to provide access to one of Workhorse's function, or a dummy function instead. One possibility would be to create an abstract parent class (Horse) specifying the interface of Workhorse, but not implementing any of the functions. Derive from it two classes, Workhorse, and TrojanHorse. TrojanHorse would implement all of the functions in the parent class as Shells, Workhorse would be as you've already created it.
The manager class could have the initialize function you're interested in, and it could store an object of type Horse. By default, the horse object could be assigned to a TrojanHorse object, but initialize would instead assign it to a Workhorse object.
This solution would avoid almost all of the speed impact from if statements, it would be maintainable in the sense that the compiler would give errors if the classes weren't changed in the proper manner, and it would still be comprehensible to another programmer looking at the code.
Great question! Its always good to make an API that is hard to use wrong, and as you are observing classes that are not fully constructed are dangerous, hard to use correctly and easy to use wrong. They set ourselves & others up for failure. I've done some refactoring on your second example to come up with a safer design that won't even allow your "do something bad" code.
The general idea was that PublicKeyCryptoProvider had too many responsibilities ( violation of SRP ):
Key generation
Key storage
Encryption
Decryption
Each one of the responsibilities has been delegated out. Now the PublicKeyCryptoProvider is more responsible for giving you the tools necessary to do encryption/decryption & key management.
#include <iostream>
#include <utility>
struct PublicKey
{
int shared;
};
struct PrivateKey
{
int secret;
};
struct KeyPair
{
PublicKey public_key;
PrivateKey private_key;
};
struct Encryptor
{
Encryptor( PublicKey shared_ )
: shared( shared_ )
{}
int Encrypt (const int &plaintext) const
{
int ciphertext;
//apply encryption algorithm on plaintext
ciphertext = plaintext * shared.shared;
return ciphertext;
}
private:
PublicKey shared;
};
struct Decryptor
{
Decryptor( PrivateKey secret_ )
: secret( secret_ )
{}
int Decrypt (const int &ciphertext) const
{
int plaintext;
//apply decryption algorithm on ciphertext
plaintext = ciphertext / secret.secret;
return plaintext;
}
private:
PrivateKey secret;
};
class PublicKeyCryptoProvider
{
public:
KeyPair GenerateKeys()
{
KeyPair keys;
//generate pk and sk
keys.public_key.shared = 4;
keys.private_key.secret = 4;
return keys;
}
Decryptor BuildDecryptor( PrivateKey key )
{
return Decryptor( key );
}
Encryptor BuildEncryptor( PublicKey key )
{
return Encryptor( key );
}
/* These are replaced by directly building an Encryptor/Decryptor
when you have a public or private key.
void SetPublicKey (const PublicKey &pk)
{
this->pk = pk;
}
const PublicKey &GetPublicKey () const
{
return this->pk;
}
*/
};
int main ()
{
/* scenario 1: */
PublicKeyCryptoProvider cryptoProvider;
auto keys = cryptoProvider.GenerateKeys();
auto decryptor = cryptoProvider.BuildDecryptor(keys.private_key);
auto encryptor = cryptoProvider.BuildEncryptor(keys.public_key);
std::cout << decryptor.Decrypt( encryptor.Encrypt(3) ) << std::endl;
/* /scenario 1: */
/* scenario 2: */
PublicKeyCryptoProvider cryptoProvider1;
auto keys1 = cryptoProvider1.GenerateKeys();
PublicKeyCryptoProvider cryptoProvider2;
auto encryptor2 = cryptoProvider2.BuildEncryptor(keys.public_key);
int ciphertext = encryptor2.Encrypt(3);
std::cout << decryptor.Decrypt(ciphertext) << std::endl;
// I Can't do anything bad - the API has protected me from doing bad things! Yeah!
//std::cout << cryptoProvider2.Decrypt(ciphertext) << std::endl;
/* /scenario 2: */
return 0;
}
You mentioned that you didn't think inheritance is the way to go, but there is a fairly clean way to do this with minimal inheritance.
A couple of design patterns are useful here. If you split the interface away from the implementation and think of the implementations as "always return an error" and "do something useful", you can view these two implementations as strategies and the interface as a proxy.
The proxy always forwards on it's calls to an implementation, and there is always an implementation (no need to check a flag).
The interface is initialized with a default implementation that causes an error of some kind (assert, throw, etc.). This is an example
Here's an example that I threw together that compiles with Clang 3.2:
#include <iostream>
#include <memory>
#include <cassert>
#include <stdexcept>
// Base class that defines the signatures of the functions to be forwarded.
// Another nice benefit is that each implementation can store whatever
// specific data they need.
class Impl {
public:
virtual void FuncA() = 0;
};
typedef std::unique_ptr<Impl> ImplPtr;
class ErrorImpl : public Impl {
public:
virtual void FuncA() {
assert(!"Don't call this before calling InitializeImpl!");
throw std::runtime_error("Don't call this before calling InitializeImpl!");
}
};
class OtherImpl : public Impl {
public:
void FuncA() {
std::cout << "Some other useful functionality here.\n";
}
};
// This is the class that user's will call.
class Proxy {
public:
Proxy() : impl_( ImplPtr(new ErrorImpl) ) {}
void InitializeImpl( ImplPtr ptr ) {
// You must std::move std::unique_ptr's.
impl_ = std::move( ptr );
}
void FuncA() { impl_->FuncA(); }
private:
ImplPtr impl_;
};
int main( int, char**) {
Proxy p;
// p.FuncA(); // asserts & throws.
p.InitializeImpl( ImplPtr(new OtherImpl) );
p.FuncA();
return 0;
}
If you must delay the object initialization, I would propose the usage of a proxy with an access operator throwing if the proxy is not initialized. Initialize the proxy whenever you want. You don't need an if check in each of your methods, but that check if moved to the proxy.
Some smart pointer would have been handy. But, as far as I know they don't throw if the containing pointer is uninitialized. So, you might need one of your own as given below.
#include <iostream>
class Workhorse
{
public:
void SetData (const int &data)
{
this->data = data;
}
int GetData () const
{
return this->data;
}
private:
int data;
};
template <typename T> class Proxy
{
public:
Proxy() : myObject(0)
{
}
Proxy(T* anObj) : myObject(anObj)
{
}
~Proxy()
{
delete myObject;
myObject = 0;
}
T* operator ->()const
{
if(NULL == myObject)
{
throw; // Bad object. Substitute an appropriate exception code.
}
return myObject;
}
private:
T* myObject;
};
class Worker
{
public:
Worker ()
{
}
~Worker ()
{
}
void Initialize (const int &data)
{
horse = new Workhorse;
horse->SetData(data);
}
void Action () const
{
// Here no need to check if the horse is initialized.
std::cout << horse->GetData() << std::endl;
}
private:
Proxy<Workhorse> horse;
};