Naw*_*waz 85

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.
   //...
};
Run Code Online (Sandbox Code Playgroud)

要了解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
Run Code Online (Sandbox Code Playgroud)

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!
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`朋友T;`只是C++ 11,尽管MSVC允许它在C++ 03中作为扩展. (3认同)
  • 私人继承在这里可以吗?实际上,我已经测试过私有虚拟继承可以正常工作.我可以说使用私有继承会更合理吗?毕竟,你不希望有人使用`Base*`来操作`A`对象,Base类不是为OOP设计的.这只是一个实用工具.Plz评论. (2认同)

Dav*_*eas 10

有两种方式,简单便宜,而且正确.@Naveen和@Nawaz的两个答案处理正确的答案,需要手动为每个实际想要密封的类创建一个封闭器类.

adobe库中使用的不是万无一失的方法是使用模板化的类.问题是你不能将模板参数声明为朋友,这意味着你必须切换private到不太安全protected:

template <typename T>
class sealer {
protected: sealer() {}
};
class sealed : virtual sealer<sealed> {};
Run Code Online (Sandbox Code Playgroud)

你可以使用宏自动化它(我不记得Adobe代码中宏的确切味道):

#define seal( x ) virtual sealer<x>
class sealed : seal(sealed) 
{};
Run Code Online (Sandbox Code Playgroud)

现在,这将抓住错误地尝试继承的人,而不知道他们不应该:

class derived : sealed {};
int main() {
   derived d;  // sealer<T>::sealer() is protected within this context
}
Run Code Online (Sandbox Code Playgroud)

但它不会抑制真正想要派生的人,因为他们可以通过从模板本身获取来获得对构造函数的访问:

class derived : sealed, sealer<sealed> {};
int main() {
   derived d;
};
Run Code Online (Sandbox Code Playgroud)

我不确定这是否会在C++ 0x中发生变化,我想我会回想一下关于是否允许类模板与其中一个参数建立联系的讨论,但是粗略地搜索草案我无法说清楚.如果允许那么这将是一个很好的通用解决方案:

template <typename T>
class sealer {
   sealer() {}
   friend class T; // Incorrect in C++03
};
Run Code Online (Sandbox Code Playgroud)


AzP*_*AzP 9

C++ 11增加了阻止从类继承或仅防止派生类中的重写方法的能力.这是通过特殊标识符完成的final.例如:

class Base final { };

class Derived1 : Base { }; // ill-formed because the class Base has been marked final
Run Code Online (Sandbox Code Playgroud)

要么

class Base {
    virtual void f() final;
};

class Derived : Base {
    void f(); // ill-formed because the virtual function Base::f has been marked final
Run Code Online (Sandbox Code Playgroud)

请注意,final不是语言关键字.它在技术上是一个标识符; 它只在特定情况下使用时才有特殊意义.在任何其他位置,它可以是有效的标识符.