C++ Design – Using Macros to Define Classes That Fit a Pattern

ccode-qualitydesignmacros

I've got a set of classes that all inherit from a base class that are responsible for different functions (sort of like a group of "operators") They all work on the same input and output the same output type, just different operations are performed internally with some other state. They need to be serialized to JSON and factoried from a UI.

My requirements are that people need to be able to work on this without struggling to understand it. I was hoping some one else had employed this in a different project with other people and could tell me whether or not this is a bad idea from experience and why.

In order to do this I've employed maps that associate the class name to the constructor and method to serialize the class. At first I was manually entering class information in a separate file that housed these maps, then I found a method to do so utilizing static class objects, where they automatically add themselves to the parent abstract classes static map. Because this was needed for each class no matter what, and had the same exact format except for the name of the class used, I created two macros to help with this (so you would only need do MACRO_TAG_CLASS(classname) inside class declaration and MACRO_REGISTER_CLASS(classname) after declaration).

Now I've come to refactor the way I was doing serialization and GUI display, allowing less work for people creating new classes of this type and making them more versatile for how I now want to use them. I ended up needing to use QT properties in the same way with every class, so I decided to make a macro to deal with this as well (Note I'm using boost pre-processor to help out)

Now I have classes that all look like this:

class MyClass :
        public AbstractBase {
Q_OBJECT
private:
    TypeA m_foo;
    TypeB m_bar;
public:
    MACRO_TAG_CLASS(MyClass)

MACRO_ADD_PROPERTIES((TypeA, foo), (TypeB, bar))
//adds qt properties, signals, and adds the strings of the properties to a list for the class

   //other class functions...
   //constructor that is different per class

   //function every class in this heirarchy has, sort of operator(), 
   //but class is doesn't correspond 1:1 with the concept of an operator, so not a functor.
    AbstractBase *baz(X *x) override;

    virtual ~MyClass() = default;
};
MACRO_REGISTER_CLASS(MyClass)

and I was thinking of changing them to something that looks like this:

#define START_CLASS_OF_BASE(CLASS_NAME, ...)\
class CLASS_NAME : public AbstractBase { \
Q_OBJECT \
 public: \
    MACRO_TAG_CLASS(CLASS_NAME) \
MACRO_ADD_PROPERTIES(__VA_ARGS__) \
private:

#define END_CLASS_OF_BASE(CLASS_NAME) \
}; \
    MACRO_REGISTER_CLASS(CLASS_NAME)

START_CLASS_OF_BASE(MyClass, (TypeA, foo), (TypeB, bar))
private:
    TypeA m_foo;
    TypeB m_bar;
public:
   //other class functions...
   //constructor that is different per class

    AbstractBase *baz(X *x) override;

    virtual ~MyClass() = default;
END_CLASS_OF_BASE(MyClass)

Note this pattern only appears in this particular class hierarchy, other people will need to maintain this code eventually, and there are about 20 classes that fit this pattern.

Best Answer

I oppose to use macros instead of normal class here because:

  1. It is harder to debug, especially when it has compile error

  2. If the cost of creating a new class easily is harder to maintain later, I prefer do more works to create a class but easier to maintain later

  3. I believe a gold of quote would be applied in this case :"Reading code usually cost more time than writing code"

Related Topic