如何在C ++中定义密封类?

时间:2011-01-17 12:12:01

标签: c++ class inheritance derived-class sealed

如何阻止类被其他类继承。

6 个答案:

答案 0 :(得分:82)

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

要了解final的其他用法,请参阅我的回答:


C ++ 03解决方案

Bjarne Stroustrup's code我可以阻止那些来自我班级的人吗?

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!

答案 1 :(得分:10)

有两种方式,简单便宜,而且正确。 @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
};

答案 2 :(得分:7)

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不是语言关键字。它在技术上是一个标识符;它只在特定情况下使用时才有特殊意义。在任何其他位置,它可以是有效的标识符。

答案 3 :(得分:0)

基于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;
}

答案 4 :(得分:-1)

以下代码显示了如何在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方式。

答案 5 :(得分:-11)

你做不到。 C ++不是Java或C#。恕我直言也没有意义。