Как остановить класс для наследования другим классом.
Как определить закрытый класс в С++?
Ответ 1
С++ 11 решение
В С++ 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, см. мой ответ здесь:
С++ 03 решение
Код Бьярна Страуструпа: Могу ли я остановить людей, выходящих из моего класса?
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 касаются правильного, требующего ручного создания класса герметика для каждого класса, который вы действительно хотите запечатать.
Неверный способ, который используется в библиотеках adobe, использует для этого шаблонный класс. Проблема в том, что вы не можете объявить аргумент шаблона в качестве друга, а это значит, что вам нужно перейти от 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;
};
Я не уверен, изменится ли это в С++ 0x, я думаю, что я вспоминаю некоторые дискуссии о том, разрешено ли шаблону класса подружиться с одним из его аргументов, но в беглом поиске по проекту я не могу сказать, Если бы это было разрешено, это было бы прекрасным общим решением:
template <typename T>
class sealer {
sealer() {}
friend class T; // Incorrect in C++03
};
Ответ 3
С++ 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 не является ключевым словом языка. Это технически идентификатор; он приобретает особое значение при использовании в этих конкретных контекстах. В любом другом месте он может быть допустимым идентификатором.
Ответ 4
На основе 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;
}
Ответ 5
Следующий код показывает, как определить запечатанный класс в 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, также в других ответах показан последний способ C++ 11 для достижения того же самого с помощью ключевого слова final
.
Ответ 6
Вы не можете. С++ не является Java или С#. И также нет смысла, когда-либо, ИМХО.