wake-up-neo.com

Wie definiere ich eine versiegelte Klasse in C++?

So halten Sie die Klasse an, um von anderen Klassen geerbt zu werden.

51
Mahantesh

C++ 11-Lösung

In C++ 11 können Sie eine Klasse mit dem Schlüssel final in der Definition versiegeln:

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.
   //...
};

Um die anderen Verwendungen von final kennenzulernen, sehen Sie meine Antwort hier:


C++ 03-Lösung

Bjarne Stroustrups Code : Kann ich verhindern, dass Leute aus meiner Klasse kommen?

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

Wir können also eine Vorlage verwenden, um das Usable_lock-Generic genug zu machen, um jede Klasse zu versiegeln:

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!
82
Nawaz

Es gibt zwei Möglichkeiten, die einfache billige und die richtige. Die beiden Antworten von @Naveen und @Nawaz beziehen sich auf die richtige Antwort, die die manuelle Erstellung einer sealer - Klasse für jede Klasse erfordert, die Sie tatsächlich versiegeln möchten.

Die nicht narrensichere Methode, die in den Adobe-Bibliotheken verwendet wird, ist die Verwendung einer Klasse mit Vorlagen. Das Problem ist, dass Sie das Vorlagenargument nicht als Freund deklarieren können. Dies bedeutet, dass Sie von private zu der weniger sicheren protected wechseln müssen:

template <typename T>
class sealer {
protected: sealer() {}
};
class sealed : virtual sealer<sealed> {};

Und Sie können es mit einem Makro automatisieren (ich erinnere mich nicht an den genauen Verlauf des Makros in Adobes Code):

#define seal( x ) virtual sealer<x>
class sealed : seal(sealed) 
{};

Dies wird Menschen fangen, die versehentlich versuchen zu erben, ohne zu wissen, dass sie dies nicht tun sollten:

class derived : sealed {};
int main() {
   derived d;  // sealer<T>::sealer() is protected within this context
}

Es wird jedoch nicht Personen daran hindern, die wirklich davon ableiten wollen, da sie Zugriff auf den Konstruktor erhalten können, indem sie von der Vorlage selbst ableiten:

class derived : sealed, sealer<sealed> {};
int main() {
   derived d;
};

Ich bin nicht sicher, ob sich dies in C++ 0x ändern wird. Ich denke, ich erinnere mich an einige Diskussionen darüber, ob eine Klassenvorlage mit einem ihrer Argumente befreundet sein könnte, aber bei einer flüchtigen Suche durch den Entwurf kann ich nicht wirklich sagen. Wenn dies erlaubt wäre, wäre dies eine gute generische Lösung:

template <typename T>
class sealer {
   sealer() {}
   friend class T; // Incorrect in C++03
};

C++ 11 bietet die Möglichkeit, das Erben von Klassen zu verhindern oder das Überschreiben von Methoden in abgeleiteten Klassen zu verhindern. Dies geschieht mit der speziellen Kennung final. Zum Beispiel:

class Base final { };

class Derived1 : Base { }; // ill-formed because the class Base has been marked final

oder

class Base {
    virtual void f() final;
};

class Derived : Base {
    void f(); // ill-formed because the virtual function Base::f has been marked final

Beachten Sie, dass final kein Sprachschlüsselwort ist. Es ist technisch eine Kennung; es erhält nur eine besondere Bedeutung, wenn es in diesen spezifischen Zusammenhängen verwendet wird. An anderen Orten kann es eine gültige Kennung sein.

7
AzP

Basierend auf Bjarne Stroustrup's http://www.stroustrup.com/bs_faq2.html#no-derivation FAQ Mit kleinen Modifikationen ohne Freundschaftsschlüsselwortnutzung:

// SEALED CLASS DEFINITIONS
class Usable_lock {
protected:
    Usable_lock() {}
    Usable_lock(const Usable_lock&) {}
};
#define sealed_class private virtual Usable_lock

// SEALED CLASS USAGE EXMAPLES
class UsableLast : sealed_class {
public:
    UsableLast(){}
    UsableLast(char*){}
};
class DD : public UsableLast {};

// TEST CODE
template <class T> T createInstance() {
    return T();
}
int main()
{
    createInstance<UsableLast>();
//  createInstance<DD>();
    return 0;
}
0
bruziuz