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.