0

Good Evening

Currently I'm developing something like C++ MVC framework. It's just for education purposes right now - to see if I can make such a thing and understand it completely and to learn new things about this (not so) beauty language.

I've got abstract class for models that would be extended to make a new one. They are registered by a Register singleton and loaded with loader class by string name.

So, right now, a blank new modules are written in this manner:

# myModel.hpp

class myModel: public cinite::core::abstract::Model {
    public:
        myModel(cinite::core::Loader &_loader): cinite::core::abstract::Model(_loader){};

    private:
        static cinite::core::registerClass<myModel> __cinite_reg;
};

# myModel.cpp
cinite::core::registerClass<myModel> myModel::__cinite_reg("myModel");

It's quite a lot of writting, so I decided to simplify this by adding macros like

#define CINITE_MODEL_CONSTRUCT(CLASS) \
    CLASS(cinite::core::Loader &_loader): cinite::core::abstract::Model(_loader){};

#define CINITE_DEFINE_REGISTRY(CLASS) \
    static cinite::core::registerClass<CLASS> __cinite_reg;

#define CINITE_REGISTER(CLASS, NAME) \
    cinite::core::registerClass<CLASS> CLASS::__cinite_reg(#NAME);

So the whole thing would be this way right now:

# myModel.hpp

class myModel: public cinite::core::abstract::Model {
    public:
        CINITE_MODEL_CONSTRUCT(myModel);

    private:
        CINITE_DEFINE_REGISTRY(myModel);
};

# myModel.cpp

CINITE_REGISTER(myModel, myModel);

And obviously it looks much more easier (at least to me) to write.

But there is still that constructor thing - I wonder is there any possibility to get around this (as this would look exactly the same for every class, except for the class name) and use default abstract::Model constructor? I would use rather a simple virtual void __init() method, with no arguments, if someone would need any initialization in his model and bypass the whole loader-thing.

So, finally, how can I use default abstract::Model constructor with it's arguments to make blank models easier to write? I need loader to be passed to the model as it's the thing that makes everything other possible (loading other models, drivers and other things).

And another, bonus question: do this looks good, or is there anything that makes it terrible in use?

For ones curiosity - registry-thing looks like this right now

# registry.hpp

namespace cinite {
    namespace core {

        template <typename T>
        abstract::Abstract *abstractCreator(Loader &_loader) {
            return new T(_loader);
        }
        typedef abstract::Abstract* (*abstractCreatorFunc)();

        class Registry {
            public:
                static Registry& getInstance() {
                    static Registry instance;
                    return instance;
                }
                Registry(){};
                Registry(Registry const&)       = delete;
                void operator=(Registry const&) = delete;

                const static unsigned int t_abstract   = 0;
                const static unsigned int t_model      = 1;

                ...

                static void registerModel(std::string name, abstractCreatorFunc creator);
                static abstractCreatorFunc getModelCreator(std::string name);

                ...

            private:
                std::map<std::string, abstractCreatorFunc> _models;

                ...

        };

        template<typename T>
        struct registerClass {
            registerClass(const std::string name) {
                switch (T::__regType) {
                    case Registry::t_model:
                        Registry::registerModel(name, (abstractCreatorFunc)abstractCreator<T>);
                        break;

                    ...
                }

            }
        };
    }
}


# registry.cpp

using namespace cinite::core;

void Registry::registerModel(std::string name, abstractCreatorFunc creator) {
    Registry::getInstance()._models[name] = creator;
}

abstractCreatorFunc Registry::getModelCreator(std::string name) {
    Registry &reg = Registry::getInstance();
    std::map<std::string, abstractCreatorFunc>::iterator it;

    it = reg._models.find(name);

    if (it == reg._models.end()) {
        throw exception::registryException(exception::registryException::MODEL_NOT_REGISTERED, "Model not found in registry (" + name + ")");
    }

    return (abstractCreatorFunc)it->second;
}

By the way: the solution for registry comes from this solution (thanks to @johannes-schaub-litb).

Community
  • 1
  • 1

1 Answers1

1

Could you use the using keyword? For example, this code compiles:

#include <iostream>

class A 
{
public:
    A(int a) : mA(a) {}
    virtual ~A() {}
    virtual void print() { std::cout << mA << std::endl; }
protected:
    int mA;
};

class B : public A
{
public:
    using A::A; // use the constructor from A
};

int main()
{
    B b(10);
    b.print();
    return 0;
}
pingul
  • 3,351
  • 3
  • 25
  • 43