How to define sealed class in C++?
C++11 adds the ability to prevent inheriting from classes or simply preventing overriding methods in derived classes. This is done with the special identifier final
. For example:
class Base final { };
class Derived1 : Base { }; // ill-formed because the class Base has been marked final
or
class Base {
virtual void f() final;
};
class Derived : Base {
void f(); // ill-formed because the virtual function Base::f has been marked final
Note that final is not a language keyword. It is technically an identifier; it only gains special meaning when used in those specific contexts. In any other location, it can be a valid identifier.
There are two ways, the simple cheap, and the correct one. The two answers by @Naveen and @Nawaz deal with the correct one, that requires manual creation of a sealer class for each class that you actually want to seal.
The not fool-proof way, which is used in the adobe libraries is using a templated class for that. The problem is that you cannot declare the template argument as a friend, and that means that you will have to switch from private
to the less safe protected
:
template <typename T>
class sealer {
protected: sealer() {}
};
class sealed : virtual sealer<sealed> {};
And you can automate it with a macro (I don't remember the exact flavor of the macro in Adobe's code):
#define seal( x ) virtual sealer<x>
class sealed : seal(sealed)
{};
Now this will catch people that mistakenly try to inherit without knowing that they shouldn't:
class derived : sealed {};
int main() {
derived d; // sealer<T>::sealer() is protected within this context
}
But it will not inhibit people that really want to from deriving, as they can gain access to the constructor by deriving from the template themselves:
class derived : sealed, sealer<sealed> {};
int main() {
derived d;
};
I am not sure whether this will change in C++0x, I think I recall some discussions on whether a class template would be allowed to befriend one of it's arguments, but in a cursory search through the draft I cannot really tell. If that was allowed then this would be a fine generic solution:
template <typename T>
class sealer {
sealer() {}
friend class T; // Incorrect in C++03
};
C++11 solution
In C++11, you can seal a class by using final
keyword in the definition as:
class A final //note final keyword is used after the class name
{
//...
};
class B : public A //error - because class A is marked final (sealed).
{ // so A cannot be derived from.
//...
};
To know the other uses of final, see my answer here:
- What is the purpose of the "final" keyword in C++11 for functions?
C++03 solution
Bjarne Stroustrup's code : Can I stop people deriving from my class?
class Usable;
class Usable_lock {
friend class Usable;
private:
Usable_lock() {}
Usable_lock(const Usable_lock&) {}
};
class Usable : public virtual Usable_lock {
public:
Usable();
Usable(char*);
};
Usable a;
class DD : public Usable { };
DD dd; // error: DD::DD() cannot access
// Usable_lock::Usable_lock(): private member
Generic_lock
So we can make use of template to make the Usable_lock
generic enough to seal any class:
template<class T>
class Generic_lock
{
friend T;
Generic_lock() {} //private
Generic_lock(const Generic_lock&) {} //private
};
class Usable : public virtual Generic_lock<Usable>
{
public:
Usable() {}
};
Usable a; //Okay
class DD : public Usable { };
DD dd; //Not okay!