tags:

views:

350

answers:

3

Example:

template<class T>
class Base {
public:
    Base();
    friend class T;
};

Now this doesn't work... Is there a way of doing this?

I'm actually trying to make a general class sealer like this:

class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : private virtual ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // Cannot be instantiated
};

I found this example on this site somewhere but I can't find it... (here)

I know there are other ways of doing this but just now I'm curious if you actually can do something like this.

+1  A: 

Do you really need to do this? If you want to prevent someone from deriving from your class, just add a comment and make the destructor non-virtual.

rlbond
:) Sometimes the best technical answer is not technical at all.
David Rodríguez - dribeas
Sure, but it's better if illegal usage can be flagged at compile time, is it not? It's the same principle as using an assert() instead of a comment -- wouldn't you agree that assert() is useful?
j_random_hacker
@rlbond: Sometimes you just can't make the destructor non-virtual, because it might have a base class where the destructor is virtual.
Armen Tsirunyan
+5  A: 

It is explicitly disallowed in the standard, even if some versions of VisualStudio do allow it.

C++ Standard 7.1.5.3 Elaborated type specifiers, paragraph 2

3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed. ]

I recognize the code above as a pattern to seal (disallow the extension of) a class. There is another solution, that does not really block the extension but that will flag unadvertidly extending from the class. As seen in ADOBE Source Library:

namespace adobe { namespace implementation {
template <class T>
class final
{
protected:
   final() {}
};
}}
#define ADOBE_FINAL( X ) private virtual adobe::implementation::final<T>

with the usage:

class Sealed : ADOBE_FINAL( Sealed )
{//...
};

While it allows extension if you really force it:

class SealBreaker : public Sealed, ADOBE_FINAL( Sealed )
{
public:
   SealBreaker() : adobe::implementation::final<Sealed>(), Sealed() {}
};

It will restrict users from mistakenly do it.

David Rodríguez - dribeas
+2  A: 

This topic is covered in the C++ Parashift Faq in the section #35.16

Edison Gustavo Muenz
The problem at hand is slightly different, dealing with the imposibility of decaring a template parameter as friend of the templated class. The link you post (recommended for everyone) deals with the declaration and usage of friends of the template that are not its argument.
David Rodríguez - dribeas