Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define sealed class in C++?

How to stop the class to be inherited by other class.

like image 352
Shashi Avatar asked Jan 17 '11 12:01

Shashi


People also ask

How do you declare a sealed class named user?

If you want to declare a method as sealed, then it has to be declared as virtual in its base class. In the following code, create a sealed class SealedClass and use it from Program. If you run this code then it will work fine.

What is the sealed class?

Sealed classes and interfaces represent restricted class hierarchies that provide more control over inheritance. All direct subclasses of a sealed class are known at compile time. No other subclasses may appear outside a module within which the sealed class is defined.

When should a class be declared as sealed?

Marking a class as Sealed prevents tampering of important classes that can compromise security, or affect performance. Many times, sealing a class also makes sense when one is designing a utility class with fixed behaviour, which we don't want to change.

Why do we create sealed class in C#?

We use sealed classes to prevent inheritance. As we cannot inherit from a sealed class, the methods in the sealed class cannot be manipulated from other classes. It helps to prevent security issues.


2 Answers

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!
like image 111
Nawaz Avatar answered Oct 20 '22 17:10

Nawaz


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
};
like image 10
David Rodríguez - dribeas Avatar answered Oct 20 '22 17:10

David Rodríguez - dribeas