for my project I need to create singletons of a generic type.
Those singletons manage the generic types in a std::map with ID to Object.
Here is my used code:
template <typename tComponent>
class InternalComponent {
public:
static InternalComponent& getInstance() {
static InternalComponent s_result;
return s_result;
}
void add(const tComponent& component, int id) {
m_components[id] = component;
}
void remove(int id) {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_components.find(id);
if (it == m_components.end()) {
throw std::runtime_error("Component can't be found.");
}
m_components.erase(it, m_components.end());
}
void replace(const tComponent& component, int id) {
auto it = m_components.find(id);
if (it == m_components.end()) {
throw std::runtime_error("Component can't be found.");
}
m_components[id] = component;
}
tComponent* get(int id) {
return &m_components[id];
}
private:
InternalComponent() {};
InternalComponent(const InternalComponent&);
InternalComponent & operator = (const InternalComponent &);
std::mutex m_mutex;
std::map<int, tComponent> m_components;
};
In order to delete all Components with a specific ID from each singleton, I have to keep track of each created instance of the singleton.
At this point I'm stuck.
The first problem is the generic type which can't be saved to a vector.
I would bypass this with an Baseclass and derive InternalComponent from it.
However I would still be unable to save the references to a vector.
Also I'm unsure how to check if the singleton is created for the first time, without using an if-statement in each getInstance call, to avoid duplicates entries in my list of created singletons.
My final question would be: How can I manage each created instance of an InternalComponent in a single list.
I figured out how I can keep track of all my created template based singleton.
#include <iostream>
#include <vector>
class Base {
public:
virtual void delete(int id) = 0;
};
std::vector<Base*> test;
template<typename T>
class S : public Base
{
public:
void delete(int id) override {
//delete the component
};
static S& getInstance()
{
static S instance;
return instance;
}
private:
S() {
test.push_back(this);
};
public:
S(S const&) = delete;
void operator=(S const&) = delete;
};
int main()
{
S<int>::getInstance();
S<char>::getInstance();
S<char>::getInstance();
for (auto s : test) {
s->delete(666);
}
exit(0);
}
I use an abstract class to later store a template based class inside a vector. The class provides the functions which are later needed. The constructor only gets called once, which allows me to store the this pointer and avoiding uneeded checks.
Related
I did a small exemple to try to explain you with my poor english what I want to do :).
I have a main class who is my engine. This is my parent class of several children.
this is the parent class :
#include <string>
#include <iostream>
#include <vector>
template <typename Type>
class A
{
public:
A(std::string const &str)
: m_str(str)
{
}
void run(void) const {
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++) {
if(m_str == ACTIONS[i].key) {
return ((*(this).*ACTIONS[i].f)(m_str));
}
}
}
protected:
typedef struct s_action {
std::string key;
void (Type::*f)(std::string const &);
} t_action;
static t_action const ACTIONS[];
std::string m_str;
};
class B : public A<B>
{
public:
B(std::string const &str);
protected:
static t_action const ACTIONS[];
void error(std::string const &str);
void success(std::string const &str);
};
I would like to call children method with table pointer of member function in this parent class A::run as you can see above
This code does not compile.
I know it's not possible to have a static variable virtual, but it's
exactly that I need to do have for A::ACTIONS. I absolutely need to initialise B::ACTIONS to A::run works.
In first Is it possible? Have you got a small exemple of this case?
This is the end of my small code :
#include "Class.hpp"
B::t_action const B::ACTIONS[] = {
{"ERROR", &B::error},
{"SUCCESS", &B::success},
{"", nullptr}
};
B::B(std::string const &str)
: A<B>(str)
{
}
void B::error(std::string const &str) {
std::cerr << str << std::endl;
}
void B::success(std::string const &str) {
std::cout << str <<std::endl;
}
And the main:
#include "Class.hpp"
int main() {
B b("SUCCESS");
b.run();
return (0);
}
I didn't try, normally this code should Display SUCCESS on stdout
Thank you for your help
void run(void) const
{
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++)
if (m_str == ACTIONS[i].key)
return ((*(this).*ACTIONS[i].f)(m_str));
}
There are multiple reasons why this fails to compile. Not one, but several reasons. This entire dispatching mechanism must be completely redesigned.
The first order of business is that this is a
void run(void) const
A const class method.
The method pointer in question is:
void (Type::*f)(std::string const &);
The method pointer is not const, but mutable. From an existing const class method, you can only invoke other const methods. You cannot invoke non-const methods, either directly or indirectly via a method pointer, from a const class methods.
So the first order of business is to change this to
void (Type::*f)(std::string const &) const;
This also means that all your methods, in the child class, error() and success(), must also be const class methods too.
If it's necessary to use this dispatch mechanism with non-const methods, the run() method cannot be a const class method itself. But this is not the only problem here, so I'll continue with the const method, at hand.
return ((*(this).*ACTIONS[i].f)(m_str));
The this here, is a A<Type>. This is a method of that class. That's what this is here.
The method pointer, f is pointer to a method of Type, not A<Type>. Type is a subclass of A<Type>, and you cannot convert a pointer or a reference to a base class to a pointer or a reference to a subclass, any more than you can take a pointer to A, and convert to a pointer to B when B inherits from A. C++ does not work this way.
The solution is simple, and requires only a few small tweaks. This run() should take a reference to const Type &, and invoke the method via the passed-in reference, then a replacement abstract run() method invokes it, passing *this as a parameter:
public:
virtual void run()=0;
protected:
void run_me(const Type &me) const
{
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++)
if (m_str == ACTIONS[i].key)
return ((me.*ACTIONS[i].f)(m_str));
}
Then, each subclass that inherits this template only needs to implement a simple facade:
class B : public A<B>
{
public:
void run() const override
{
run_me(*this);
}
EDIT: This addresses the compilation error, but additional work is needed to deal with the fact that static class members cannot be overridden. The solution is also pretty simple: also leverage virtual class methods in order to implement this.
Remove the declaration of ACTIONS from the template base class, and replace it with an abstract function:
virtual const t_action *get_actions() const=0;
And use it in run_me():
const t_action *ACTIONS=this->get_actions();
The rest of run_me() remains as is, and then implement get_actions() in the child class:
const t_action *get_actions() const override
{
return ACTIONS;
}
Pretty much everything else remains the same.
The problem is that A will always use is own defined set of actions, not B's.
You don't need to create A at all, as you want to use B methods and list of methods.
Let's say that you create first a run call function:
template<typename T>
void run(T* obj, const std::string method)
{
const auto& available_methods = obj->get_methods();
auto iter = available_methods.find(method);
if(iter == available_methods.end())
{
// Handle this case
}
std::invoke(iter->second, obj); //C++17, or (obj->*(iter->second))();
}
Now for the class B, you need something very simple:
class B
{
public:
typedef std::unordered_map<std::string, void(B::*)()> MethodMap;
void foo();
static MethodMap& get_methods()
{
static MethodMap map{{"foo", &B::foo}};
return map;
}
};
Populate the map with get_methods() in the static function, and then call run through:
int main()
{
B b;
run(&b, "foo");
}
If you are going to use CRTP, IMO you need to google for CRTP first.
By the way here's a quick direct ans 2 your q:
template<typename crtp_child>
class crtp_base{
using crtp_target=crtp_child;
auto crtp_this(){
return static_cast<crtp_target*>(this);
};
auto crtp_this() const {
return static_cast<crtp_target const*>(this);
};
public:
void run(){
auto range=crtp_this()->actions.equal_range(m_str);
for(auto entry:range)
(crtp_this()->*(entry.second))(m_str);
};
protected:
crtp_base(std::string str):
m_str(str)
{};
std::string m_str;
//...
};
struct crtp_user:
crtp_base<crtp_user>
{
using crtp_base::crtp_base;//ctor fwding
protected:
friend class crtp_base<crtp_user>;
std::unordered_multimap<std::string, void (crtp_user::*)(std::string)> actions;
//...
};
I am trying to build a generic event system. The Delegates and Events should not know anything about the other and a Manager will handle everything.
With this in mind I created a templated delegate/listener is made up of a function pointer and templated parameters.
class IDelegate
{
public:
IDelegate() {};
virtual ~IDelegate() = 0;
virtual void exec() = 0;
};
template<class Class, typename... Args>
class Delegate : public IDelegate
{
public:
typedef (Class::*Function)(Args);
Delegate(Class* inst, Function func) : instance(inst), function(func) {};
~Delegate() { instance = nullptr };
void exec(Args args)
{
instance->function(args);
}
private:
Class* instance;
Function function;
};
I did something similar on the Event side. The Events being made up of an ID and the Arguments that will need to be past to the function pointer.
class IEvent
{
public:
IEvent() {};
virtual ~IEvent() = 0;
};
template<typename... Args>
class Event : IEvent
{
public:
Event(ID eventID, Args args) : id(eventID), arguments(args) {};
~Event() = default;
ID id;
Args arguments;
};
I choose to use templates in the hope of not needing to manually create every event/delegate class that may be needed.
Lastly I wanted to make a Manager that would be a singleton.
//EventHandler.h
#pragma once
#include <string>
#include <unordered_map>
#include <queue>
#include "Event.h"
typedef std::string ID;
typedef std::unordered_multimap<ID, void*> Listeners;
class EventHandler
{
public:
EventHandler(const EventHandler& copy) = delete;
~EventHandler();
EventHandler& operator= (const EventHandler& rhs) = delete;
void Initialize();
template<class Class, class TEvent>
void Run();
void Shutdown();
static Listeners::iterator& Register(ID id, IDelegate* listener);
static void Deregister(Listeners::iterator& iterator);
static void Post(IEvent* evnt);
private:
static Listeners listeners;
static std::queue<IEvent*> events;
static EventHandler* instance;
EventHandler() {};
EventHandler(const EventHandler& copy);
EventHandler& operator= (const EventHandler& rhs);
};
//EventHandler.cpp
#include "EventHandler.h"
EventHandler::~EventHandler()
{
instance = nullptr;
}
void EventHandler::Initialize()
{
instance = this;
}
void EventHandler::Run()
{
//TODO: Determine the Event and cast or instantiate to the right class
IEvent* evnt = events.front; //This should not be IEvent*, but Event<>*
events.pop();
listeners[evnt->id].exec(evnt->arguments); //The delegate may need to be casted too.
}
void EventHandler::Shutdown()
{
instance = nullptr;
}
Listeners::iterator& EventHandler::Register(ID id, IDelegate* listener)
{
Listeners::iterator iter = listeners.emplace(id, listener);
return iter;
}
void EventHandler::Deregister(Listeners::iterator& iterator)
{
listeners.erase(iterator);
}
void EventHandler::Post(IEvent* evnt)
{
events.emplace(evnt);
}
Where I'm running into trouble is figuring out what Event I'm actually using in Run(). If possible I would like to do this without a switch or something similar as that would defeat the use of the templated classes. I have considered making the function pointer all be the same signature as this would simplify some of the code, but would make the system less flexible.
Thank you for any help.
My library uses the Object Factory technique to create "Nodes" that have a specific purpose. By default these Nodes do their job but are quite basic. I want to allow the users of my library to be able and create a sub-class of the provided "Node" class to define their own functionality while keeping the base functionality of a node intact.
Here is some example code to demonstrate my question:
class Node
{
int SomeValue;
public:
Node(int Value)
{
SomeValue = Value;
}
~Node()
{
// Cleanup the node
}
};
class NodeFactory
{
std::vector<Node*> Nodes;
public:
void CreateNode(int Value)
{
Nodes.push_back(new Node(Value));
}
};
This shows the basic Object Factory technique, now for my question.
Can I add a function to the "NodeFactory" such as "void SetType()" and be able to pass in a sub-class of "Node" which in turn will have it create that sub-class during the "CreateNode" function?
Thank you very much for your time it is greatly appreciated.
EDIT:
The usage of "void CreateNode()" is abstracted away from the end user thus my curiosity towards a "void RegisterType()" function where the user can register their sub-class for the factory to create instead of the base-class I provide.
EDIT:
A more concise way to phrase the question would be as follows: How can I let the user tell the factory to create instances of their sub-class, if they've defined one, instead of my default base-class? I want to thank everyone again for their time and effort in answering this question.
I think the problem here is combining the following two requirements:
You want to use the quite simple function void CreateNode(int) to create any node.
You want the user to be able to create new nodes derived from Node and use your factory to create them.
Now what I would suggest is something similar to R Sahu however without following the Factory pattern as strictly as he did.
You could get the functionality you seek by requiring your users to pass a small Creator-object to your factory. (Note that this is deviating a bit from the classical Factory-pattern. As you basically make your NodeFactory into a delegator using the creator-classes.)
class NodeCreator {
public:
virtual Node* create(int) = 0;
virtual ~NodeCreator() = default;
};
class DefaultNodeCreator : public NodeCreator {
public:
virtual Node* create(int value) {
return new Node(value);
}
};
Now I as a user will create my own node:
class MyNode : public Node {
private:
int otherValue;
public:
MyNode(int nodeValue, int otherValue )
: Node(nodeValue), otherValue(otherValue)
{}
// Implement other functionality...
};
class MyNodeCreator : public NodeCreator {
private:
// I added otherNodeValue to show that Creators can have a state.
int otherNodeValue;
public:
MyNodeCreator(int otherNodeValue ) : otherNodeValue(otherNodeValue) {}
virtual Node* create(int value) {
return new MyNode(value, otherNodeValue);
}
};
Now finally in your Factory class you need to set it like this:
class NodeFactory
{
std::vector<Node*> Nodes;
std::unique_ptr<NodeCreator> activeCreator;
public:
NodeFactory() {
setNodeCreator(nullptr);
}
void createNode(int Value)
{
Nodes.push_back( activeCreator->create(Value) );
}
void setNodeCreator( std::unique_ptr<NodeCreator> creator ) {
if (creator == nullptr) {
activeCreator.reset( new DefaultNodeCreator() );
else {
activeCreator.reset(creator);
}
}
};
To use it from main:
int main() {
NodeFactory nf;
nf.createNode(1); // Creating Node(1)
nf.createNode(2); // Creating Node(2)
nf.setCreator( new MyNodeCreator(5) );
// Any nodes created now will be of type MyNode
// with otherNodeValue == 5.
nf.createNode(2); // Creating MyNode(2, 5)
nf.createNode(3); // Creating MyNode(3, 5)
}
A final note:
If you intend for your users to implement subclasses of Node and use these with polymorphism as shown above, it is important that you declare Node's destructor as virtual. You have no guarantee that your users will not use dynamic allocation in their subclasses, so it is your responsibility to ensure that their destructors get called.
A Factory Pattern is meant to create objects with an indirect reference. For example, the user should be able call:
Node* node = Factory::createNode("MyNodeType");
If there is a Factory that can create such a Node, then the function returns with a pointer to a MyNodeType object. Otherwise, it return NULL.
In order for this function to work, a Factory has to be registered that can construct objects of type MyNodeType. We will have to trust that such a Factory creates Nodes of that type.
The classes involved in this patter:
The abstract base class Node.
The abstract base class Factory.
Concrete sub-class of Node called MyNodeType.
Concreate sub-class of Factory. Let's call it MyNodeTypeFactory.
Here's such a skeletal structure.
Node.h:
class Node
{
virtual ~Node() = 0;
};
Factor.h:
#include <string>
class Factory
{
public:
static void registerFactory(std::string const& productType,
Factory* factory);
static Node* creatNode(std::string const& productType);
private:
virtual Node* createNode();
};
Factory.cc:
#include <map>
typedef std::map<std::string, Factory*> FactoryMap;
static FactoryMap& getFactoryMap()
{
static FactoryMap factoryMap;
return factoryMap;
}
static void registerFactory(std::string const& productType,
Factory* factory)
{
getFactoryMap()[productType] = factory;
}
static Node* creatNode(std::string const& productType)
{
FactoryMap& factoryMap = getFactoryMap();
FactoryMap::iterator iter = factoryMap.find(productType);
if ( iter == factoryMap.end() )
{
// Unknown product.
return NULL;
}
return iter->second->createNode();
}
MyNodeType.h:
#include "Node.h"
class MyNodeType : public Node
{
MyNodeType() {}
virtual ~MyNodeType() {}
};
MyNodeTypeFactory.h:
#include <Factory.h>
class MyNodeTypeFactory : public Factory
{
public:
virtual Node* createNode();
};
MyNodeTypeFactory.cc:
#include "MyNodeTypeFactory.h"
struct RegistrationHelper
{
MyNodeTypeFactorHelper()
{
Factory::registerFactory("MyNodeType", new MyNodeTypeFactory());
}
};
static RegistrationHelper helper;
Node* MyNodeTypeFactory::createNode()
{
return MyNodeType();
}
You probably even don't need a RegisterType()... The simplest way is to use C++11 (it allows you to derive nodes w/ different, than a base Node, constructor signatures):
#include <iostream>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
class Node
{
int SomeValue;
public:
Node(int Value)
: SomeValue{Value}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
// ATTENTION Make destructor virtual!
virtual ~Node()
{
// Cleanup the node
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class SomeOtherNode : public Node
{
std::string SomeStringValue;
public:
SomeOtherNode(int Value, const std::string StringValue)
: Node{Value}
, SomeStringValue{StringValue}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~SomeOtherNode()
{
// Cleanup the string node
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class NotARealNode
{
int SomeValue;
public:
NotARealNode(int Value)
: SomeValue{Value}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~NotARealNode()
{
// Cleanup the node
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class NodeFactory
{
std::vector<std::unique_ptr<Node>> Nodes;
public:
template <typename NodeType, typename... Args>
typename std::enable_if<
std::is_base_of<Node, NodeType>::value
>::type CreateNode(Args&&... args)
{
Nodes.push_back(
std::unique_ptr<NodeType>{
new NodeType{std::forward<Args>(args)...}
}
);
}
};
int main()
{
NodeFactory f;
f.CreateNode<Node>(123);
f.CreateNode<SomeOtherNode>(123, "Hello");
#if 0
// ATTENTION It wont compile, cuz NotARealNode is not a child of Node!
f.CreateNode<NotARealNode>(123);
#endif
return 0;
}
Output:
zaufi#gentop>/work/tests> g++ -std=c++11 -o fff fff.cc
zaufi#gentop>/work/tests> ./fff
Node::Node(int)
Node::Node(int)
SomeOtherNode::SomeOtherNode(int, std::string)
virtual Node::~Node()
virtual SomeOtherNode::~SomeOtherNode()
virtual Node::~Node()
You could (should?) use polymorphism for that. Just derive from NodeFactory (make CreateNode a virtual function) and have it spawn Nodes of your desired type. Of course you would have to move the Nodes vector into a different class.
I am having trouble in finding simple and elegant design for the following scenario. Class Worker uses template class Helper to do some work. In the simple scenario it looks like this:
template<typename T>
class Helper {
public:
void Help(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T m_data;
}
class SimpleWorker {
public:
SimpleWorker() : m_helper(SimpleData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
}
Helper<SimpleData> m_helper;
}
Things get complicated for me when the template argument is more complex and is of the same business domain of the worker. The worker needs to use the helper but it would also need to call some methods on the data object that the helper doesn't even know about (in this design). Something like:
template<typename T>
class Helper {
public:
Helper(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T m_data;
}
class ComplexWorker {
public:
ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
m_helper.GetData().DoSomethingComplexNotConst(); // <-------------
}
Helper<ComplexData> m_helper;
}
The obvious problem is that I can't call not const function on Data() result. Making Data() non-const seems like a bad idea as Helper is used in different contexts as well. My goal is to find an elegant way to alter ComplexData using its member functions from ComplexWorker
The ComplexData needs to be altered in the first place so that Helper can continue working with the altered data.
EDIT: Changed Helper construction to copy the provided data to better resemble actual flow
I think it's best to let Helper have only static functions, not maintaing state (as you create temporary ComplexData() in ComplexWorker in your own code). Pass the data by reference or const-reference depending on whether you need to modify or not.
// primary template
template<typename T>
class Helper {
public:
static void help(T const& data) const {} // non-modifying
};
// specialization for ComplexData
template<>
class Helper<ComplexData> {
public:
static void help(ComplexData const& data) const { } // non-modifying
static void DoSomethingComplexNotConst(ComplexData& data) // modifying
{
// your implementation here
}
};
class ComplexWorker {
public:
ComplexWorker() : m_data(ComplexData()) {} // create new data
void DoWork()
{
Helper<ComplexData>::help(m_data);
Helper<ComplexData>::DoSomethingComplexNotConst(m_data); // <--- now no problem
}
private:
ComplexData m_data;
};
Note that I made a template specialization for the ComplexData. There is some code duplication in help() but you can easily extract this into a common non-member helper function.
Seems to me that it depends on what Helper is actually doing. Your example just gives a constructor and an accessor but I doubt that is all it does in practice.
Have you considered simply using inheritance? Your Helper template would then look like this:
template<typename T>
class Helper : public T {
Helper(T data) : T(data) {}
void Help() {};
}
In this case you could use the Helper<ComplexData> object directly in an 'is-a' relationship:
class ComplexWorker {
Helper<ComplexData> m_helper;
void DoWork()
{
m_helper.help();
m_helper.DoSomethingComplexNotConst();
}
}
Why not refer to the realization of the Container part in STL. An overload of the Data() function may achieve a ballance between safty and elegance.
template <typename T>
class Helper {
public:
Helper(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T& Data() {return m_data; }
private:
T m_data;
}
class ComplexWorker {
public:
ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
ComplexData &cd1 = m_helper.Data();
cd1.QuerySth();
const ComplexData &cd2 = m_helper.Data();
cd2.ModifySth();
}
private:
Helper<ComplexData> m_helper;
}
Suppose I have the following classes:
class BaseObject {
public:
virtual int getSomeCommonProperty();
};
class Object1: public BaseObject {
public:
virtual int getSomeCommonProperty(); // optional
int getSomeSpecificProperty();
};
class BaseCollection {
public:
virtual void someCommonTask();
};
class Collection1: public BaseCollection {
public:
virtual void someCommonTask(); // optional
void someSpecificTask();
};
Each collection, derived from BaseCollection, deals with a specific object type (and only one type). But BaseCollection should be able to perform some tasks that are common to all objects, using only common object properties in BaseObject.
Currently, I have potentially three solutions in mind:
1) Store the objects list in BaseCollection, such as:
class BaseCollection {
vector<BaseObject*> objects;
};
The problem with this solution is that when I need to perform object-specific task in Collection1, I need a dynamic_cast<>, because I don't want to use virtual inherance for specific properties, applying to only one type of object. Considering that dynamic_cast<> could potentially get called millions of time per second, this seems an issue for a performance critical application.
2) Store the objects list in Collection1, such as:
class Collection1: public BaseCollection {
vector<Object1*> objects;
}
But then I need some way to access this object list in BaseCollection, to be able to perform some common tasks on them, ideally through an iterator. I would need to create a function that return a vector for the BaseCollection, but again, this does not seem very efficient, because the only way to do that is to create a new vector (potentially containing thousands of objects)...
3) Store the objects list in BaseCollection AND Collection1:
class BaseCollection {
public:
void someCommonTask(); // Use baseObjects
virtual void addObject() = 0;
protected:
vector<BaseObject*> baseObjects;
};
class Collection1: public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
}
Where the two lists actually contain the same objects. Is that as ugly as it sounds like?
I am looking for the right/correct/best design pattern for this type of problem and none of the 3 solutions exposed above really satisfies me...
Maybe it is possible to solve that problem with templates, but then I don't see a way to store a list of polymorphic collections like this:
vector<BaseCollection*> collections;
You can store all your objects of base and derived classes in one collection through the base class (smart) pointer. Using visitor design pattern and double dispatch mechanism you can call a function only on objects of a specific type without having to expose that function in the base class interface. For example:
#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <stdio.h>
struct Visitor { // Visitor design patter
virtual void visit(struct BaseObject&) {}
virtual void visit(struct Object1&) {}
};
struct BaseObject {
unsigned ref_count_; // intrusive_ptr support
BaseObject() : ref_count_() {}
virtual ~BaseObject() {}
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
void intrusive_ptr_add_ref(BaseObject* p) { // intrusive_ptr support
++p->ref_count_;
}
void intrusive_ptr_release(BaseObject* p) { // intrusive_ptr support
if(!--p->ref_count_)
delete p;
}
struct Object1 : BaseObject {
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
void getSomeSpecificProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class T, class Functor>
struct FunctorVisitor : Visitor {
Functor f_;
FunctorVisitor(Functor f) : f_(f) {}
void visit(T& t) { f_(t); } // apply to T objects only
template<class P> void operator()(P const& p) { p->accept(*this); }
};
template<class T, class Functor>
FunctorVisitor<T, Functor> apply_to(Functor f)
{
return FunctorVisitor<T, Functor>(f);
}
int main()
{
typedef boost::intrusive_ptr<BaseObject> BaseObjectPtr;
typedef std::vector<BaseObjectPtr> Objects;
Objects objects;
objects.push_back(BaseObjectPtr(new BaseObject));
objects.push_back(BaseObjectPtr(new Object1));
for_each(
objects.begin()
, objects.end()
, boost::bind(&BaseObject::getSomeCommonProperty, _1)
);
for_each(
objects.begin()
, objects.end()
, apply_to<BaseObject>(boost::bind(&BaseObject::getSomeCommonProperty, _1))
);
for_each(
objects.begin()
, objects.end()
, apply_to<Object1>(boost::bind(&Object1::getSomeSpecificProperty, _1))
);
}
Output:
$ ./test
virtual void BaseObject::getSomeCommonProperty()
virtual void Object1::getSomeCommonProperty()
virtual void BaseObject::getSomeCommonProperty()
void Object1::getSomeSpecificProperty()
I think you should go for option 1 but use a static cast instead. After all the derived collection knows the type of the member variable for sure.
This answer explains it very well.
Id use nested adapter as in below example. You have to specialize it for every class you want to do a fancy update
!The example has memory leak - allocated A, B, Q objects are not deleted!
#include <iostream>
#include <vector>
#include <algorithm>
class Q
{
public:
virtual void Foo()
{
std::cout << "Q::Foo()" << std::endl;
}
};
class A
{
public:
virtual void Foo()
{
std::cout << "A::Foo()" << std::endl;
}
};
class B : public A
{
public:
virtual void Foo()
{
std::cout << "B::Foo()" << std::endl;
}
virtual void BFoo()
{
std::cout << "B::BFoo()" << std::endl;
}
};
template <typename ElementType>
class C
{
public:
template <typename T>
void add(T* ptr){m_Collection.push_back(std::unique_ptr<Adapter>(new ConcreteAdapter<T>(ptr)));}
void updateAll()
{
std::for_each(m_Collection.begin(), m_Collection.end(), [&](std::unique_ptr<Adapter> &adapter)->void{adapter->update();});
}
private:
class Adapter
{
public:
virtual ElementType* get() = 0;
virtual void update(){get()->Foo();}
};
template <typename T>
class ConcreteAdapter : public Adapter
{
public:
ConcreteAdapter(T* ptr) : m_Ptr(ptr){}
virtual T* get(){return m_Ptr;}
protected:
T* m_Ptr;
};
template <>
class ConcreteAdapter<B> : public Adapter
{
public:
ConcreteAdapter(B* ptr) : m_Ptr(ptr){}
virtual B* get(){return m_Ptr;}
virtual void update()
{
get()->Foo();
get()->BFoo();
}
private:
B* m_Ptr;
};
std::vector<std::unique_ptr<Adapter>> m_Collection;
};
int main()
{
C<A> c;
c.add(new A());
c.add(new B());
//c.add(new Q()); //error - correct
c.updateAll();
return 0;
}
Maybe this will do the trick here ?
class CollectionManipulator {
public:
void someCommonTask(BaseCollection& coll) {
for(unsigned int i = 0; i < coll.size(); i++)
someCommonTask(coll.getObj(i));
}
private:
void someCommonTask(BaseObject*); // Use baseObjects
};
class BaseCollection {
friend class CollectionManipulator;
private:
virtual BaseObject* getObj(unsigned int) = 0;
virtual unsigned int size() const = 0;
};
class Collection1 : public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
private:
BaseObject* getObj(unsigned int value) {
return object[value];
}
unsigned int size() const {
return objects.size();
}
}
If you want abstract your container in Collection1 (like using list instead using vector), to use it in Manipulator, create an abstract iterator...
I think the solution should be a mix of factory method pattern and template method pattern. Take a look at those to refine your design.
Edit: Here is a sample code. GenericProduct is the BaseObject, it provides two methods, one that is general (though it could be overridden), and a specific method which does nothing, it is not a pure virtual so this class can be instantiated. SpecificProduct is a subclass, which implements the specific method in some way.
Now, Factory class is an abstract class that defines an interface for creating specific products by specific factories, it defines a pure virtual method createProduct which creates the product. Two concrete factories are created GenericFactory and SpecificFactory which create specific products.
Finally, the Consumer abstract class (which corresponds to BaseCollection in your code), it defines a pure virtual method for creating a factory createFactory in order to force subclasses to create their own concrete factories (and hence, the correct products). The class also define a method fillArray (prototype pattern) to fill the array with products created by the factory.
#include <iostream>
#include <vector>
using namespace std;
class GenericProduct{
public:
virtual void getSomeCommonProperty()
{
cout<<"Common Property\n";
}
virtual void getSomeSpecificProperty()
{
cout<<"Generic Has Nothing Specific\n";
}
};
class SpecificProduct : public GenericProduct{
public:
virtual void getSomeSpecificProperty()
{
cout<<"Specific Product Has a Specific Property\n";
}
};
class Factory
{
public:
virtual GenericProduct* createProduct() = 0;
};
class GenericFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new GenericProduct();
}
};
class SpecificFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new SpecificProduct();
}
};
class Consumer
{
protected:
vector<GenericProduct*> gp;
Factory* factory;
protected:
virtual void createFactory() = 0;
public:
void fillArray()
{
createFactory();
for(int i=0; i<10; i++)
{
gp.push_back(factory->createProduct());
}
}
virtual void someCommonTask()
{
cout<<"Performaing a Common Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeCommonProperty();
}
}
virtual void someSpecificTask()
{
cout<<"Performaing a Specific Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeSpecificProperty();
}
}
};
class GenericConsumer : public Consumer
{
virtual void createFactory()
{
factory = new GenericFactory();
}
};
class SpecificConsumer : public Consumer
{
virtual void createFactory()
{
factory = new SpecificFactory();
}
};
int main()
{
Consumer* c = new GenericConsumer();
c->fillArray();
c->someCommonTask();
return 0;
}