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;
//...
};
Related
I have a base product class with a few private members and a public getter that derived classes inherit. I would like to disqualify instantiation, since the class is intended for use with an abstract factory. I thought protected con/destructors might work, however, this breaks my smart pointers. Friending seems like a useful disaster. Is there a well-known solution to this, or should I resign myself to the fact that any client who has the factory injected must also know enough to instantiate the base product?
class Product
{
private:
char type_name;
char size_name;
public:
Product(char, char);
virtual ~Product() {}
void Print();
};
Use a token key.
private:
Product(char, char);
struct key_t{explicit key_t(int){}};
static key_t key(){return key_t(0);}
public:
Product(key_t, char a, char b):Product(a,b){}
static std::shared_ptr<Product> make_shared(char a, char b){ return std::make_shared<Product>(key(),a,b); }
anyone with a Product::key_t can construct a Product without being a friend. And without the key, you cannot.
This lets Product pass creation-rights as a value.
Smart pointers with configurable destroy code can use similar techniques. But I'd just make the destructor public.
Your static member function, or friend function, which is the factory should have no problem with calling protected constructors and returning a smart pointer. Generally plan to return a std::unique_ptr<BaseClass> which can be converted into a std::shared_ptr if the caller wants that instead.
Make the virtual destructor public.
Update: Don't bother making the factory a friend. You only need to prevent the construction of the base and intermediate classes. Make them effectively hidden and private by hiding the implementation classes in their own source file. Or an anonymous namespace I suppose.
Here have some code of how I would do it:
#include <iostream>
#include <memory>
#include <string>
// ITest is the only class any other code file should ever see.
class ITest {
protected:
ITest() = default;
public:
virtual ~ITest() = 0;
virtual int getX() const = 0;
virtual int getY() const = 0;
};
// Destructors must always have an implementation even if they are pure virtual.
ITest::~ITest() {}
std::ostream &operator<<(std::ostream &os, const ITest &x) {
return os << '[' << x.getX() << ',' << x.getY() << ']';
}
// Declaration of constructTest factory function.
// Its definition should be hidden in a cpp file.
std::unique_ptr<ITest> constructTest(int x);
// The main function does not need to know anything except the ITest interface
// class and the constructTest function declaration.
int main(int argc, char *argv[]) {
int val = 0;
if (argc > 1)
val = std::stoi(argv[1]);
auto p = constructTest(val);
std::cout << *p << std::endl;
}
// These classes should be defined in a private header file or in a cpp file.
// Should not be visible to any other code. It has no business knowing.
// Hiding all of this implementation is sort of the point of abstract interface
// classes and factory function declarations.
class TestBase : public ITest {
private:
int x = 0;
int y = 0;
protected:
TestBase(int x = 0, int y = 0) : x(x), y(y){};
public:
int getX() const override { return x; }
int getY() const override { return y; }
};
class TestA final : public TestBase {
public:
TestA() = default;
};
class TestB final : public TestBase {
public:
TestB(int x, int y) : TestBase(x, y) {}
int getX() const override { return -TestBase::getX(); }
};
std::unique_ptr<ITest> constructTest(int x) {
// make_unique is c++14.
// For C++11 use std::unique_ptr<ITest>(new TestB(x, x)
if (x) {
return std::make_unique<TestB>(x, x);
// return std::unique_ptr<ITest>(new TestB(x, x));
}
return std::make_unique<TestA>();
}
The answer was to make the destructor a pure virtual AND to implement it with an empty body. That empty implementation is where I got tripped up. Print() doesn't need to be static.
Product.hpp
#include <memory>
class Product {
public:
virtual ~Product() = 0;
void Print();
protected:
char type_name{};
char size_name{};
private:
};
Product.cpp
#include "Product.hpp"
Product::~Product() {}
void Product::Print() {
//Print p
}
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).
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);
}
I have an hierarchy of classes, the base class having a function to print the class name:
#include <iostream>
using namespace std;
class base
{
public:
virtual void print_name() { cout << typeid(*this).name() << endl; };
};
class derived1 : public base { };
class derived2 : public base { };
int main ()
{
base Base;
Base.print_name();
derived1 Derived1;
Derived1.print_name();
derived2 Derived2;
Derived2.print_name();
}
The output of the above is
class base
class derived1
class derived2
which is, in fact, platform dependent.
Is there a more or less standard way to "attach" some unique name to each class, so it could be used in printname() making the output the same for all platforms (and independent of any changes made to real class names)?
Sure:
class base {
public:
virtual char const *name() const { return "base"; }
};
class derived1 : public base {
public:
virtual char const *name() const { return "derived1"; }
};
However, if you do not override name in a class, its name will be that of its superclass. That may be a bug or a feature, depending on your use case. If it's a bug, then you can add some runtime checks to make sure the method is overridden:
virtual char const *name() const {
if (typeid(*this) != typeid(base))
throw std::logic_error("name() not overridden");
return "base";
}
But you'll have to repeat this check in every implementation of name that must be overridden.
You can effectively use type_info for this.
type_info supports a before method conforming to a Weak Order, which allows its use in a std::map (for example) as long as a user-supplied predicate is provided.
struct TypeInfoLess {
bool operator()(std::type_info const* lhs, std::type_info const* rhs) const {
return lhs->before(rhs);
}
};
struct AdditionalTypeInfo {
std::string name;
};
typedef std::map<std::type_info const*, AdditionalTypeInfo, TypeInfoLess> TypeInfoMap;
Then, you can just add/search types:
template <typename T>
void add(TypeInfoMap& map, T const& t, AdditionalTypeInfo const& ati) {
map[&typeid(t)] = ati;
}
template <typename T>
AdditionalTypeInfo const* find(TypeInfoMap const& map, T const& t) {
TypeInfoMap::const_iterator it = map.find(&typeid(t));
if (it == map.end()) { return 0; }
return &it->second;
}
int main() {
TypeInfoMap timap;
add(timap, timap, { "TypeInfoMap" });
if (AdditionalTypeInfo const* const ati = find(timap, timap)) {
std::cout << ati->name << "\n";
}
}
Note: it is then your responsability to add to the map every type that you might want.
You can use template functions (or traits classes) to get names:
template<typename T> const char * ClassName(T const * objPtr);
template<> const char * ClassName<derived1>(derived1 const *objPtr) { return "derived1"; }
template<> const char * ClassName<derived2>(derived2 const *objPtr) { return "derived2"; }
(Here the function parameter is used for template parameter matching only).
And in calling code you can cast your pointer to specific class and use ClassName
derived1 * pDerived = static_cast<derived1*>(pPointer);
cout << ClassName(pDerived);
However this is all compile-time, and you will need some mechanism (like GUIDs) to identify a class at runtime (to cast it to the right pointer type). If your classes have none and you can't modify them, than I can't help you;( But you can use traits technique to localize your platform-dependent type selection code.
I think I messed up somehow in my design because I want to keep a vector of various object types. These types all share a common base class. Example:
Class Buick: AmericanCar
{
}
Class Ford: AmericanCar
{
}
then I did:
vector<AmericanCar*> cars_i_own;
Now, I have my vector of pointers but I don't have the derived class which is what I need. I thought about adding a GetType/SetType function to the base class and then use a dynamic cast. This is clunky though. Did i use the wrong design for this?
Well, what are you trying to do with it? Get the name or cost? You would have something like:
class Car
{
public:
virtual ~Car(void) {}
virtual std::string location(void) const = 0;
virtual std::string name(void) const = 0;
virtual double cost(void) const = 0;
}
class AmericanCar
{
public:
virtual ~AmericanCar(void) {}
virtual std::string location(void) const
{
return "America";
}
}
class Buick : public AmericanCar
{
public:
virtual std::string name(void) const
{
return "Buick";
}
virtual double cost(void) const
{
return /* ... */;
}
}
class Ford : public AmericanCar
{
public:
virtual std::string name(void) const
{
return "Ford";
}
virtual double cost(void) const
{
return /* ... */;
}
}
Now you can call these methods polymorphically.
This is somewhat strange, though. You don't need a different class to store names and cost like this:
class Car
{
public:
Car(const std::string& pLocation,
const std::string& pName,
double pCost) :
mLocation(pLocation),
mName(pName),
mCost(pCost)
{
}
const std::string& location(void) const
{
return mLocation;
}
void location(const std::string& pLocation)
{
mLocation = pLocation;
}
const std::string& name(void) const
{
return mName;
}
void name(const std::string& pName)
{
mName = pName;
}
const double cost(void) const
{
return mCost;
}
void cost(double pCost)
{
mCost = pCost;
}
private:
std::string mLocation;
std::string mName;
double mCost;
}
// make cars
std::vector<Car> cars;
cars.push_back(Car("America", "Buick", /* ... */));
The purpose of inheritance / polymorphism is so you don't need to care which derived type you are dealing with.
In particular I think storing data, such as make of car, country of origin etc, encoded in a class hierarchy doesn't seem to be particularly beneficial. Does an AmericanCar do something fundamentally different from, say, a Japanese car (other than consuming more fuel, which again can be better stored in a data member)?
Why do you need to know the derived class? Normally you would have virtual functions to take care of any behavior differences between the two derived classes.
The goal is that the code using the parent class shouldn't have to know the exact class it's working with.
You can use typeid to determine the derived class:
struct Base
{
virtual ~Base() {}
};
struct Derived : public Base { };
int main()
{
Base* b = new Derived();
std::cout << typeid(*b).name() << std::endl;
}
This outputs: "Derived".
But, usually with polymorphism the point is that you shouldn't be concerned with this. You simply call a base-class member function and the proper derived-class member function is called at runtime.