简体   繁体   中英

Variadic Macro for Multiple Inheritance

I have written a macro that can be added around a class definition that will effectively final-ize it (prevent subclassing). This method of finalization is a fairly common technique and is noted in the C++ FAQ :

#define FINALIZE(NAME,...) \
    NAME##Finalizer {\
        private:\
            friend class NAME;\
            inline NAME##Finalizer(void) {}\
    };\
    class NAME : public virtual NAME##Finalizer, __VA_ARGS__

For example:

class FINALIZE(Fred) {};
//The above line evaluates to:
//  class FredFinalizer {
//      private:
//          friend class Fred;
//          inline FredFinalizer(void) {}
//  };
//  class Fred : public virtual FredFinalizer, {};

class George {};
class FINALIZE(Fred2, public George) {};
//The above line evaluates to:
//  class Fred2Finalizer {
//      private:
//          friend class Fred2;
//          inline Fred2Finalizer(void) {}
//  };
//  class Fred2 : public virtual Fred2Finalizer, public George {};

class Velma : public Fred { Velma(void) {} /*Note compile error*/ };
class Velma2 : public Fred2 { Velma2(void) {} /*Note compile error*/ };

This works splendidly. The problem is that I would now like a way to "disable" the macro. That is:

class FINALIZE(Fred) {};
//The above line evaluates to:
//  class Fred {};

class George {};
class FINALIZE(Fred2, public George) {};
//The above line evaluates to:
//  class Fred2 : public George {};

The issue is that the class Fred2 : public George {}; clashes with the case where there's no inheritance ( class Fred {}; ): in the first case, there must always be a colon, in the second case, there mustn't. Note that this isn't an issue when the macro is enabled because the class always inherits from at least the NAME##Finalizer class.

How can I write a macro that does this?

I'd advice to make two macros, one for preparing finalizer, one for using:

#define PREP_FINALIZE(NAME) \
    class NAME##Finalizer {\
        private:\
            friend class NAME;\
            inline NAME##Finalizer() {}\
    }

#define FINALIZE(NAME) virtual NAME##Finalizer

So in your example:

PREP_FINALIZE(Fred);
class Fred : FINALIZE(Fred) {};

class George {};
PREP_FINALIZE(Fred2);
class Fred2 : FINALIZE(Fred2), public George {};

But what is more important you forget about to make copy constructor private. Without it your way can be cheating very easily:

// cheating :D
class Velma : public Fred, FINALIZE(Fred) { 
   Velma() : FredFinalizer(*(FredFinalizer*)0) {} /*Who said this is compiler error */ 
};

Make copy constructor of finalizer private. Or use my answer to very similar question.

For C++11 just use final ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM