他のクラスに継承されるクラスを停止する方法。
C++ 11では、次のように定義でfinal
キーワードを使用してクラスをシールできます。
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.
//...
};
Finalの他の用途を知るには、ここで私の答えを見てください:
Bjarne Stroustrupのコード :クラスから派生する人々を停止できますか?
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
したがって、テンプレートを使用してUsable_lock
すべてのクラスを封印するのに十分な汎用性:
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!
シンプルで安価な方法と正しい方法の2つの方法があります。 @Naveenと@Nawazの2つの答えは正しいものを扱っています。これは、実際にシールしたいクラスごとにsealerクラスを手動で作成する必要があります。
アドビのライブラリで使用されている絶対確実な方法は、そのためにテンプレート化されたクラスを使用しています。問題は、テンプレート引数をフレンドとして宣言できないことです。つまり、private
から安全性の低いprotected
に切り替える必要があります。
template <typename T>
class sealer {
protected: sealer() {}
};
class sealed : virtual sealer<sealed> {};
また、マクロを使用して自動化することもできます(Adobeのコードでマクロの正確なフレーバーを覚えていません)。
#define seal( x ) virtual sealer<x>
class sealed : seal(sealed)
{};
これで、誤って継承しようとする人が、自分がすべきではないことを知らずにキャッチしようとします。
class derived : sealed {};
int main() {
derived d; // sealer<T>::sealer() is protected within this context
}
しかし、テンプレート自体から派生することでコンストラクターにアクセスできるため、実際にが派生したい人を阻害することはありません。
class derived : sealed, sealer<sealed> {};
int main() {
derived d;
};
これがC++ 0xで変わるかどうかはわかりませんが、クラステンプレートがその引数の1つと友達になることを許可するかどうかについてのいくつかの議論を思い出すと思いますが、ドラフト全体の大まかな検索では私は本当に伝えることができません。それが許可された場合、これは素晴らしい汎用ソリューションになります。
template <typename T>
class sealer {
sealer() {}
friend class T; // Incorrect in C++03
};
C++ 11には、クラスからの継承を防止する機能、または派生クラスのメソッドのオーバーライドを防止する機能が追加されています。これは特別な識別子final
で行われます。例えば:
class Base final { };
class Derived1 : Base { }; // ill-formed because the class Base has been marked final
または
class Base {
virtual void f() final;
};
class Derived : Base {
void f(); // ill-formed because the virtual function Base::f has been marked final
Finalは言語キーワードではないことに注意してください。技術的には識別子です。これらの特定のコンテキストで使用された場合にのみ、特別な意味を持ちます。その他の場所では、有効な識別子にすることができます。
Bjarne Stroustrupの http://www.stroustrup.com/bs_faq2.html#no-derivation FAQフレンドキーワードを使用せずに小さな変更を加えたものに基づく:
// 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;
}