I have tried to understand what's going on in my situation from other questions in this site, but I haven't really found a good answer. I tried most of the suggestions I found but still get the same error.
I am trying to implement a factory based on a singleton and the CRTP. So I have a Singleton class, define in Singleton.h:
template<class T>
class Singleton
{
public:
static T &instance()
{
static T one;
return one;
}
Singleton(const Singleton &) = delete;
Singleton(Singleton &&) = delete;
Singleton &operator=(const Singleton &) = delete;
protected:
Singleton() = default;
};
I also have a Factory class, defined and implemented in Factory.h. The factory creates objects of a hierarchy whose base class is, for the purposes of this question, Object. These objects all have a constructor accepting a double.
class Factory : public Singleton<Factory>
{
friend class Singleton<Factory>; // to access constructor
public:
using createFunction = Object *(*)(double);
void registerObject(const std::string &, createFunction);
Object *createObject(const std::string &, double) const;
private:
Factory() = default;
std::map<std::string, createFunction> theCreatorFunctions;
};
void Factory::registerObject(
const std::string &ObjectId,
createFunction creatorFunction)
{
theCreatorFunctions.insert(
std::pair<std::string, createFunction>(
ObjectId, creatorFunction));
}
Object *Factory::createObject(
const std::string &ObjectId, double a) const
{
auto it = theCreatorFunctions.find(ObjectId);
if (it == theCreatorFunctions.end())
{
std::cout << ObjectId << " is an unknown object."
<< std::endl;
return nullptr;
}
return (it->second)(a);
}
Finally, I have a "helper" class that registers new types of Objects into the factory. Each time a new inherited object is created, say ObjectDerived, I add (in the .cpp file where ObjectDerived is implemented):
FactoryHelper<ObjectDerived> registerObjectDerived("ObjectDerived");
This creates an object of type FactoryHelper<ObjectDerived>, whose constructor handles the registration in the factory. FactoryHelper is defined (and implemented) in FactoryHelper.h:
template<class T>
class FactoryHelper
{
public:
FactoryHelper(const std::string &);
static Object *create(double);
};
template<class T>
FactoryHelper<T>::FactoryHelper(const std::string &ObjectId)
{
Factory &theFactory = Factory::instance(); // the one and only!
// if it doesn't exist at this point, it is created.
theFactory.registerObject(ObjectId, FactoryHelper<T>::create);
}
template<class T>
Object *FactoryHelper<T>::create(double a)
{
return new T(a);
}
So the problem that I have is that I get a bunch of undefined references to Factory::instance(), basically one for each type of object in the hierarchy.
If I put all in the same main.cpp file it works, but this is not a solution I'd like.
Since there is no compilation error when all your code is in one file, and you don't use any extern global objects that could cause issues with multiple files, I suspect that you have a problem in your compilation/linking script.
For the record, I can confirm that you have no intrinsic problem in the code. Adding a hierarchy
class Object
{
public:
Object(double _value) : value(_value) {}
virtual double getVal() { return value; }
private:
double value;
};
class SpecialObject : public Object
{
public:
SpecialObject(double _value) : Object(_value) {}
virtual double getVal() { double val = Object::getVal(); return val*val; }
};
the simple main routine
int main(int argc, char *argv[]) {
FactoryHelper<Object> baseMaker("Object");
FactoryHelper<SpecialObject> derivedMaker("SpecialObject");
Factory& factory = Factory::instance();
Object* a1 = factory.createObject("Object",4);
std::cout << a1->getVal() << std::endl;
Object* b1 = factory.createObject("SpecialObject",4);
std::cout << b1->getVal() << std::endl;
Object* c1 = factory.createObject("NonexistentObject",4);
return 0;
}
has the expected output:
4
16
NonexistentObject is an unknown object.
By the way, a matter of opinion: Your FactoryHelper<T> class does not achieve much, essentially acting as a shortcut for registering an object with the default allocator/constructor. At some point, making new classes stops actually saving much code. If you can use C++11, it's not much more difficult to write
factory.registerObject("SpecialObject", [] (double a) -> Object* { return new SpecialObject(a); });
If you wanted, you could add shortcut method to Factory itself:
// definition
template <class T>
void registerObject(const std::string &);
// implementation
template<class T>
void Factory::registerObject(const std::string &ObjectId)
{
registerObject(ObjectId, [] (double a) -> Object* { return new T(a); });
};
With this, the FactoryHelper class can be eliminated, and the equivalent main routine to before is
using namespace std;
int main(int argc, char *argv[]) {
Factory& factory = Factory::instance();
factory.registerObject<Object>("Object");
factory.registerObject<SpecialObject>("SpecialObject");
Object* a1 = factory.createObject("Object",4);
std::cout << a1->getVal() << std::endl;
Object* b1 = factory.createObject("SpecialObject",4);
std::cout << b1->getVal() << std::endl;
Object* c1 = factory.createObject("NonexistentObject",4);
return 0;
}
Again, if you are able to use C++11, you can always make createObject wrap the raw Object* pointer in a smart pointer (as you may well know, and maybe you have good reasons already for not doing this).
Related
I have a compile time "plugin" system based on this link, which I want to retain ownership of the plugins, which are literally unique - there should only be one instance of each type.
There is a registrar class which owns a plugin type, and owns a unique_ptr to the plugin.
I want to return a reference to the plugin whenever one is requested, to keep ownership clear.
More complete code below. Note the #define for registration in the header of a plugin.
Also, I'm renaming from Renderer in my code to Plugin here so if I've missed any that's what the random Render references are/were.
Factory class:
class PluginFactory
{
public:
// Instance of Factory
static PluginFactory& Instance();
void Register(IPluginRegistrar *Registrar, std::string name);
IPlugin& GetPlugin(std::string name);
private:
std::unordered_map<std::string, IPluginRegistrar *>_registry;
// private constructor, prevent copying
PluginFactory() : _registry() {};
PluginFactory(PluginFactoryconst&) = delete;
void operator=(PluginFactoryconst&) = delete;
};
PluginFactory& PluginFactory::Instance()
{
static PluginFactoryinstance;
return instance;
}
void PluginFactory::Register(IPluginRegistrar *registrar, std::string name)
{
if (_registry.count(name))
std::cout << name << " is already registered!\n";
else
{
std::cout << "Registering " << name << "\n";
_registry[name] = registrar;
}
}
IPlugin& PluginFactory::GetPlugin(std::string name)
{
IPluginRegistrar* registrar = _registry.at(name);
return registrar->GetPlugin();
}
#define REGISTER_PLUGIN(CLASSNAME) \
namespace { \
static MyNamespace::PluginRegistrar<CLASSNAME>\
_registrar( #CLASSNAME ); \
};
Plugin Base
class IPlugin
{
public:
IPlugin() { std::cout << "Constructing IPlugin class\n"; }
virtual void DoThing(){ std::cout << "Here's the thing from an IPlugin!\n"; };
};
Plugin Derived
class TestPlugin : public IPlugin
{
public:
TestPlugin ();
virtual void DoThing() override;
};
REGISTER_RENDERER(TestPlugin)
TestPlugin::TestPlugin () : IPlugin()
{
std::cout << "Constructing TestPlugin class\n";
}
void TestPlugin::DoThing()
{
std::cout << "Here's the thing from a TestPlugin!\n";
}
Registrar
class IPluginRegistrar
{
public:
virtual IPlugin& GetPlugin() = 0;
};
template <class T>
class PluginRegistrar: public IPluginRegistrar
{
public:
PluginRegistrar(std::string classname); // constructor registers plugin with a plugin factory
IPlugin& GetPlugin(); // GetPlugin is called by the factory
private:
std::string _name;
std::unique_ptr<IPlugin> _ptr;
};
template <class T>
PluginRegistrar<T>::PluginRegistrar(std::string classname) : _name(classname)
{
PluginFactory& factory = PluginFactory::Instance();
factory.Register(this, classname);
}
template <class T>
IPlugin &
PluginRegistrar<T>::GetPlugin()
{
if (!_ptr)
_ptr = std::make_unique<T>();
return *_ptr;
}
Code in use:
auto& factory = PluginFactory::Instance();
auto plugin= factory.GetPlugin("TestPlugin");
=> outputs confirm derived class constructed
plugin.DoThing();
=> output of IPlugin.DoThing(), not TestPlugin.DoThing()
The original version of this code returned a new unique_ptr<IPlugin> each time GetPlugin() was called, and worked great. However now I've switched return type to an IPlugin &, when I call a virtual function on the result, the base class function is called, not the derived.
auto plugin= factory.GetPlugin("TestPlugin");
This will copy the result into a new object, which will be a IPlugin (the original derived type will be sliced). You want to use a reference instead:
auto& plugin= factory.GetPlugin("TestPlugin");
You might want to make IPlugin::DoThing() a pure virtual function (i.e. virtual void DoThing() = 0) which will
Force derived classes to implement it
Prevent you from having an object of type IPlugin, i.e. make your original code fail to compile
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;
//...
};
This is a C++(11) question.
I have a object Obj myObj encapsulating an object f of type MyType.
Depending on runtime context, the object fshould behave differently.
One natural way of implementing this would be for the class Obj to encapsulate a pointer to an abstract base class MyType, which would, depending on the context point to different (public) child of MyType, such as MyType1, MyType2, etc.
However, I'm not very keen on Obj "suffering" the consequences of MyType being polymorphic, i.e. having to deal with a pointer. In particular, if I make it a std::unique_ptr<MyType>, it implies that Obj can either not be copied or that one needs to give it a proper copy constructor that deals with copying MyType ressources.
In my opinion, MyType being polymorphic shouldn't be Obj's problem.
I came with the following classes. Essentially the idea is to hide the pointer within MyTypeprivate attributes. In addition my second question concerns the fact that concrete implementations of MyTypeImpl may share some code shouldn't be repeated. I've put that in a class from which concrete implementations privately inherit.
I'm curious what more expert developers than me would think about it. Is it too heavy "just to hide the pointer"? Is there a better way to do it?
#include <iostream>
#include <memory>
// a "standard" implementation of MyType
class MyTypeImpl
{
public:
virtual double operator()(double a) = 0;
virtual int implType() const = 0;
virtual void complexStuff() const = 0;
};
// some internal stuff common to all implementations
class MyTypeImplInternals
{
protected:
MyTypeImplInternals(int value):factor_{value}{}
int factor_;
void longCommonFunction() const{ std::cout << "I'm doing complex stuff common to all interfaces " << factor_ << "\n" ;}
};
// one specific implementation
class MyTypeImpl1: public MyTypeImpl, private MyTypeImplInternals
{
public:
MyTypeImpl1(int factor):MyTypeImplInternals{factor}{};
virtual double operator()(double a) override {return factor_*a;}
virtual int implType() const override {return 1;}
virtual void complexStuff() const override { longCommonFunction(); }
};
// a second implementation
class MyTypeImpl2: public MyTypeImpl, private MyTypeImplInternals
{
public:
MyTypeImpl2(int factor):MyTypeImplInternals{factor}{};
virtual double operator()(double a) override {return factor_*a;}
virtual int implType() const override {return 2;}
virtual void complexStuff() const override { longCommonFunction(); }
};
class MyTypeImplFactory
{
public:
static std::unique_ptr<MyTypeImpl>createMyTypeImpl(int implementationType)
{
switch(implementationType)
{
case 1:
return std::unique_ptr<MyTypeImpl> (new MyTypeImpl1(12));
case 2:
return std::unique_ptr<MyTypeImpl> (new MyTypeImpl2(22));
default:
throw std::runtime_error("implementation does not exist...\n");
return nullptr;
}
}
};
// my type
class MyType
{
public:
MyType(int implementationType)
{
implPtr_ = MyTypeImplFactory::createMyTypeImpl(implementationType);
}
MyType(MyType const& source)
: implPtr_{ MyTypeImplFactory::createMyTypeImpl(source.implType()) }
{
}
double operator()(double a){return (*implPtr_)(a);}
int implType() const {return implPtr_->implType();}
void complexStuff() const {implPtr_->complexStuff();}
private:
std::unique_ptr<MyTypeImpl> implPtr_;
};
class Obj
{
private:
MyType f;
public:
Obj(int dim):f{dim}{}
Obj(Obj&& sourceToMove) = default;
Obj(Obj const& source) = default;
void doStuff() {std::cout << "I'm doing stuff() " << f(2) << std::endl; f.complexStuff();}
};
int main()
{
Obj myObj{1}, myObj2{2};
myObj.doStuff();
myObj2.doStuff();
Obj myObj3{std::move(myObj2)}; // myObj2 now dead
Obj myObj4{myObj};
myObj3.doStuff();
myObj4.doStuff();
}
link to online compiler : http://cpp.sh/8rhyy
Here the implementations are very dumb ones to serve as an example. An application for this design could be for instance a Solver (Obj) that solves some kind of physics Equation (MyType) which exact definition depends on the dimensionality of the problem, equation in 1D space is not the same as in 2D or in 3D. Solver's code would be completely independent on Equation's dimensionality and also wouldn't have to deal with a pointer. Equation would hide its 1D, 2D, or 3D implementation from outside's world.
(was originally a post on code review that was put on Hold because to abstract)
This proposed class design appears to have an obvious problem. The polymorphic type is referenced by a std::unique_ptr:
std::unique_ptr<MyTypeImpl> implPtr_;
Obj's default copy constructor, and assignment operator will end up transferring the held pointer to the new object, leaving the std::unique_ptr in the original object staring at a nullptr. Not good.
At the bare minimum this should be either a std::shared_ptr, or Obj's copy constructor and assignment operator will need to instantiate a new implPtr_. Note that with the easy std::shared_ptr fix the result of the copy constructor and an assignment operator is having multiple instances of Obj referencing the same instance of MyTypeImpl, which may or may not be an issue.
A much simpler class design is simply have MyTypeImpl1 and MyTypeImpl2 be subclasses of Obj, implementing the required polymorphic behavior.
I just refactored your codes.
#include <iostream>
#include <memory>
// !abstraction
class MyType
{
public:
virtual double operator()(double a) = 0;
virtual int implType() const = 0;
virtual void complexStuff() const = 0;
};
// !!MyTypeImplInternals could be a super class of MyTypeImpl* if it has properties(such as factor_) or just some static functions.
class MyTypeImplInternals
{
public:
MyTypeImplInternals(int value):factor_{value}{}
int factor_;
void longCommonFunction() const{ std::cout << "I'm doing complex stuff common to all interfaces " << factor_ << "\n" ;}
};
// one specific implementation
class MyTypeImpl1: public MyType
{
MyTypeImplInternals internal_;
public:
MyTypeImpl1(int factor):internal_{factor}{};
virtual double operator()(double a) override {return internal_.factor_*a;}
virtual int implType() const override {return 1;}
virtual void complexStuff() const override { internal_.longCommonFunction(); }
};
// a second implementation
class MyTypeImpl2: public MyType
{
MyTypeImplInternals internal_;
public:
MyTypeImpl2(int factor):internal_{factor}{};
virtual double operator()(double a) override {return internal_.factor_*a;}
virtual int implType() const override {return 2;}
virtual void complexStuff() const override { internal_.longCommonFunction(); }
};
std::unique_ptr<MyType> createMyType(int implementationType)
{
switch(implementationType)
{
case 1:
return std::unique_ptr<MyType> (new MyTypeImpl1(12));
case 2:
return std::unique_ptr<MyType> (new MyTypeImpl2(22));
default:
throw std::runtime_error("implementation does not exist...\n");
return nullptr;
}
}
class Obj
{
private:
std::unique_ptr<MyType> f_;
public:
Obj(int dim):f_(createMyType(dim)){}
Obj(Obj&& sourceToMove) : f_(std::move(sourceToMove.f_)) {}
Obj(Obj const& source) : f_(createMyType(source.f_->implType())) {}
void doStuff() {std::cout << "I'm doing stuff() " << (*f_)(2) << std::endl; f_->complexStuff();}
};
int main()
{
Obj myObj{1}, myObj2{2};
myObj.doStuff();
myObj2.doStuff();
Obj myObj3{std::move(myObj2)}; // myObj2 now dead
Obj myObj4{myObj}; //!!Bad idea to share an implementation to more Objs.
myObj3.doStuff();
myObj4.doStuff();
}
Given the following type hierarchy
class Base { public: virtual ~Base(); }
class OurDervied : public Base {}
class TheirDerived : public Base {}
class General { public: virtual ~General(); }
class MySpecial : public General {};
class YourSpecial : public General {};
I have a function f(Base *bp).
In f, I want to create an object with type that depends on the type passed in. For example, f creates a MySpecial when receiving an instance of OurDerived, and creates a YourSpecial when receiving an instance of TheirDerived.
I think I can do this with dynamic_cast. It probably requires trying to cast the received object repeatedly until a match is found (non-nullptr returned).
Another option is giving OurDerived, TheirDerived, etc a unique tag and then use a switch case construct to create MySpecial, YourSpecial, etc.
Are there any other options for mapping class types in C++?
Manual Type Switching
If the types you want to create have no common ancestor, you have no other option but use a
if (dynamic_cast<const DerivedA *>(&base))
{
// Create an object of some type.
}
else if (dynamic_cast<const DerivedB *>(&base))
{
// Create an object of some other type.
}
else if (dynamic_cast<const DerivedC *>(&base))
{
// Create an object of yet aother type.
}
else
{
// Handle the case that no type was matched. Maybe use a default or
// issue an error.
}
cascade and there is no direct way you can return the created object because a function cannot decide at run-time what return type it wants to have. The only way out would be to use type erasure or ugly unions.
Lookup Table with Factory Functions
Fortunately, this is not what you have to do if all the types you want to create are derived from a common base class, as you have indicated in the comments. In this case, you can map the typeid of an object to a factory function that creates the appropriate object. As usual with run-time polymorphism, this requires a heap allocation.
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
// Use the object. It can also be returned.
}
I have made the std::map<std::type_index, std::function<FactoryT()>> static so it is created only once for the entire run-time of the program. It is not clear whether or not this is beneficial in your particular situation. Maybe benchmark it.
Here is a complete working example.
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <typeindex>
#include <typeinfo>
struct Base
{
virtual ~Base() = default;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
std::cout << base << " was mapped to " << *o_uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Output:
DerivedA was mapped to Special1
DerivedB was mapped to Special2
DerivedC was mapped to Special3
Visitor Pattern
Of course, you should ask yourself the question why you actually want to do this. There are for sure legitimate applications of this technique but taking an abstract type and then taking action based on its dynamic type is usually a sign of over-abstraction and makes for poorly maintainable code. Did you consider adding the factory directly to Base?
struct Base
{
virtual ~Base() = default;
virtual std::unique_ptr<General>
getDealer() = 0;
// ...
};
The Derived classes can then override getDealer to do what the factories lambdas did in the above example.
If this seems to intrusive (maybe the Base class shouldn't know anything about the General class at all), you could consider using the visitor pattern. It is a bit more work but allows for better decoupling. There is plenty of information available on this pattern so I'll only show its application to your specific problem and refer you to your favorite search engine if you need more explanation.
#include <iostream>
#include <memory>
#include <string>
struct BaseVisitor;
struct Base
{
virtual ~Base() = default;
virtual void
accept(BaseVisitor&) const = 0;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual void
accept(BaseVisitor& vtor) const override;
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct BaseVisitor
{
virtual ~BaseVisitor() = default;
virtual void
visit(const DerivedA&) = 0;
virtual void
visit(const DerivedB&) = 0;
virtual void
visit(const DerivedC&) = 0;
};
// Cannot be defined earlier because we need the complete type of BaseVisitor.
template<char Token>
void
Derived<Token>::accept(BaseVisitor& vtor) const
{
vtor.visit(*this);
}
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
struct Mapper : BaseVisitor
{
std::unique_ptr<General> uptr {};
virtual void
visit(const DerivedA&) override
{
this->uptr.reset(new Special1 {});
}
virtual void
visit(const DerivedB&) override
{
this->uptr.reset(new Special2 {});
}
virtual void
visit(const DerivedC&) override
{
this->uptr.reset(new Special3 {});
}
};
Mapper visitor {};
base.accept(visitor);
std::cout << base << " was mapped to " << *visitor.uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Note how we have nicely broken the coupling between Base and General. On the down side, we had to introduce some kind of parent-to-child dependency via the BaseVisitor class.
This solution also gets completely rid of any explicit run-time type inference and elegantly lets the dynamic dispatch machinery do all the magic behind the scenes.
Yes, you can delegate type mapping to derived classes:
class Base
{
public:
virtual General* map() = 0;
};
class OurDerived: public Base
{
protected:
General* map()
{
// compute Type* for OurDerved
}
};
class TheirDerived: public Base
{
protected:
General* map()
{
// compute Type* for TheirDerived
}
};
It's hard to say without knowing what responsibilities your function has, or how you feel about coupling {My|Your}Special to {Our|Their}Derived.
Is Base constructible? Is Base or its derived classes allowed to have virtual methods? If you already incurred the cost of a vtable, I would delegate the responsibility to the derived types themselves, and explicitly make the method abstract on Base to force each derivation to explain itself in this regard.
Are MySpcial / YourSpecial related in the type hierarchy? Otherwise you are better off experimenting with explicit template instantiations of a helper function.
I am using a factory class to produce a number of little classes from memory pools. These little classes are constant once they are returned by the factory.
Currently a typical declaration of one of these little objects goes something like this:
class LittleObject
{
public:
...//non-getter and setter member functions
int getMemberVariable1() const;//should be accessible to everyone
void setMemberVariable1(int newMemberVariable1Value);//should only be accessible to factory class
...//more getters and setters
private:
...
};
So, as you can see the getters and setters are both in the public area. But the only time the values should be set is during the time it is being built by the factory class. Now, I can clearly see one option where I move the setter functions to private access and make the factory a friend of the LittleObject class. I find this option a bit inelegant because it exposes other private member functions to the factory. Private member functions which the factory has no business accessing.
So my question is this: What is the best method making it so that only the factory class can use the setter functions?
I would use a friend class:
class LittleObject
{
friend class LittleObjectFactory;
public:
int getMemberVariable();
private:
void setMemberVariable( int value );
};
I would really prefer to friend the factory, but if you need stronger
encapsulation, at the expense of elegance, mabe it can be done
struct LittleData;
class Factory
{
public:
void MakeLittle(LittleData&);
};
struct LittleData
{
int data1;
float data2;
};
class LittleObject
{
public:
LittleObject(const LittleObject&) = default;
LittleObject& operator=(const LittleObject&) = default;
int GetData1() const { return data.data1; }
float GetData2() const { return data.data2; }
static LittleObject MakeOne( Factory& f )
{
LittleObject obj;
f.MakeLittle(obj.data);
return obj;
}
private:
LittleObject();
LittleData data;
};
Looking at what I just wrote... I really prefer friend
Another possibility is stencils.
By that I mean static instances of each LittleObject preset to the required configuration so that the factory simply needs to make a copy.
The copy can be made via the copy constructor or, if you don't want to make one of those (and the objects are trivial) then you could use memcpy().
Here is an example using copy constructors:
class LittleObject1
{
int a;
int b;
public:
LittleObject1(const LittleObject1& o): a(o.a), b(o.b) {}
LittleObject1(int a = 0, int b = 0): a(a), b(b) {}
static LittleObject1 stencil;
int get_a() const { return a; }
int get_b() const { return b; }
};
LittleObject1 LittleObject1::stencil(3, 7); // preset values
class LittleObject2
{
std::string s;
public:
LittleObject2(const LittleObject2& o): s(o.s) {}
LittleObject2(const std::string& s = ""): s(s) {}
static LittleObject2 stencil;
std::string get_s() const { return s; }
};
LittleObject2 LittleObject2::stencil("hello"); // preset values
class Factory
{
public:
template<typename Type>
Type* create() const
{
return new Type(Type::stencil); // make a copy of the preset here
}
};
int main()
{
Factory fact;
LittleObject1* o1 = fact.create<LittleObject1>();
std::cout << o1->get_a() << '\n';
std::cout << o1->get_b() << '\n';
LittleObject2* o2 = fact.create<LittleObject2>();
std::cout << o2->get_s() << '\n';
}
This would only be useful if the values are preset and don't need calculating at run-time.
Rely on const-correctness
You say the objects are constant when they are returned by the factory.
In that case why not just return const objects:
class Factory
{
public:
std::unique_ptr<const DynamicLittleObject> createDynamicLittleObject();
const AutomaticLittleObject createAutomaticLittleObject();
};
Then just ensuring to write their functionality in a const-correct way will give the correct access control.
Some might worry about the case the user might cast away the constness, but there's only so much that is worth doing to protect them from themselves.
You could make the factory a static member function of each object. So each object type knows how to create itself. Then you can have some kind of template function to make creating them a little less typing.
Something a bit like this:
class LittleObject1
{
int a = 0;
int b = 0;
public:
virtual ~LittleObject1() {}
static LittleObject1* create()
{
LittleObject1* o = new LittleObject1;
o->a = 1;
o->b = 2;
return o;
}
};
class LittleObject2
{
std::string s;
public:
virtual ~LittleObject2() {}
static LittleObject2* create()
{
LittleObject2* o = new LittleObject2;
o->s = "hello";
return o;
}
};
template<typename Type>
Type* createType(Type*)
{
return Type::create();
}
int main()
{
LittleObject1* o1 = createType(o1);
LittleObject2* o2 = createType(o2);
}