如何阻止类被其他类继承。
6 回答
C++11解决方案
final
在 C++11 中,您可以通过在定义中使用关键字来密封类:
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 的其他用途,请在此处查看我的答案:
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
通用锁
所以我们可以利用模板来使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!
有两种方法,一种是简单便宜的,一种是正确的。@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;
};
我不确定这是否会在 C++0x 中发生变化,我想我记得一些关于是否允许类模板与其中一个论点成为朋友的讨论,但在草稿中粗略搜索时,我真的无法分辨。如果允许,那么这将是一个很好的通用解决方案:
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常见问题解答,在没有使用朋友关键字的情况下进行了小修改:
// 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#。恕我直言,也没有任何意义。