他のクラスに継承されるクラスを停止する方法。
6 に答える
C++11ソリューション
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.
//...
};
ファイナルの他の使用法を知るには、ここで私の答えを参照してください:
C++03ソリューション
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
Generic_lock
したがって、テンプレートを使用して、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つの答えは正しいものを扱っており、実際に封印したいクラスごとにシーラークラスを手動で作成する必要があります。
アドビライブラリで使用されている絶対確実ではない方法は、そのためにテンプレート化されたクラスを使用することです。問題は、テンプレート引数をフレンドとして宣言できないことです。つまり、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は言語キーワードではないことに注意してください。技術的には識別子です。これらの特定のコンテキストで使用された場合にのみ、特別な意味が得られます。その他の場所では、有効な識別子にすることができます。
BjarneStroustrupのhttp://www.stroustrup.com/bs_faq2.html#no-derivationFAQに基づいており、友人のキーワードを使用せずに少し変更を加えています。
// 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;
}
次のコードは、C ++/CLIで封印されたクラスを定義する方法を示しています。
class A sealed
{
//here goes the class code
};
class B : public A
{
};
現在、B:は「封印された」と宣言されているため、Aから継承できません。また、封印されたキーワードの詳細な説明は、http://msdn.microsoft.com/en-us/library/0w2w91tf.aspxにあります。
更新:C ++ / CLIを追加しました。また、他の回答でも、final
キーワードを使用して同じことを実現する最新のC++11の方法が示されています。
それはいけません。C ++はJavaまたはC#ではありません。そしてまた、私見には意味がありません。