更简单“防止派生类”在C ++中 [英] Simpler "Preventing derived classes" in C++

查看:147
本文介绍了更简单“防止派生类”在C ++中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有一个合理的理由阻止某些类派生,Bjarne给出一个解决方案这里



但是,我想起了:

  class final {
protected:
final(){} // line 3
};

class B:private virtual final {
};

class D:public B {// line 9
};

int main(){
B b;
D d; // line 14
}



当尝试编译时,会得到:

  foo.cpp:在构造函数'D :: D()':
foo.cpp:3:error:'final: :final()'被保护
foo.cpp:9:错误:在此上下文中
foo.cpp:在函数'int main()'中:
foo.cpp:14:note :合成方法'D :: D()'首先需要这里

我的解决方案是否适用于所有情况? IMHO,因为类 final 是通用的,不需要预先知道类,以防止派生。

  class YourSealedClass:private virtual final {}; 
class HerSealedClass:public YourSealedClass,private virtual final {
};

注意,甚至没有恶意,合同被打破。 CRTP的改进是:

  template< typename T> 
class seal
{
protected:
seal(){}
〜seal(){}
};
class YourSealedClass:private virtual seal< YourSealedClass> {};

这将捕获先前的错误,因为她的代码是:

  class HerSealedClass:public YourSealedClass,private virtual seal< HerSealedClass> {}; 

由于她不是继承自 seal< YourSealedClass> 编译器会抓住它。



这种方法的问题是它不阻止一些顽固的(恶意的)程序员写:

  class MalignClass:public YourSealedClass,private virtual seal< YourSealedClass> {}; 

成为密封类的孩子,并获得访问自己的类。 p>

在C ++ 0x中,我相信(必须重新检查它),他们会提出一个限制,即模板不能使用模板参数,这将是对类封装器的通用类型安全解决方案的良好步骤:

  template< typename T& 
class seal {
friend class T; // illegal in C ++ 03
seal(){};
〜seal(){};
};
class MySealedClass:private virtual seal< MySealedClass>
{};

这种方法的优点(目前不可用)是因为构造函数和析构函数是私有的实例化类型。因为你正在使用CRTP继承一个特定的实例化,传递你自己的类型作为参数,你告诉编译器只有你可以实际上实例化你的基地,所有的部分都到位。 p>

Going under the assumption that there is a legitimate reason for preventing derivation from some class, Bjarne gives a solution here for the answer to "Can I stop people deriving from my class?"

However, I thought of:

class final {
protected:
  final() { }         // line 3
};

class B : private virtual final {
};

class D : public B {  // line 9
};

int main() {
  B b;
  D d;                // line 14
}

When trying to compile, one gets:

foo.cpp: In constructor ‘D::D()’:
foo.cpp:3: error: ‘final::final()’ is protected
foo.cpp:9: error: within this context
foo.cpp: In function ‘int main()’:
foo.cpp:14: note: synthesized method ‘D::D()’ first required here 

Does my solution work for all cases? IMHO, it's better because the class final is generic and doesn't require foreknowledge of the class to prevent derivation from.

解决方案

The solution is rather bad, it could be improved with CRTP (adobe does so) but it won't be a complete solution. The problem with your code is that another programmer that does not want to break your contract (she is a good person) but does not know that she should not derive from your class might want to lock others from deriving from her own class:

class YourSealedClass : private virtual final {};
class HerSealedClass : public YourSealedClass, private virtual final {
};

Note that there is not even malign intention, and the contract is broken. The improvement with CRTP would be:

template <typename T>
class seal
{
protected:
   seal(){}
   ~seal(){}
};
class YourSealedClass : private virtual seal<YourSealedClass> {};

This will catch the previous mistake, as her code would be:

class HerSealedClass : public YourSealedClass, private virtual seal<HerSealedClass> {};

And as she is not inheriting from seal<YourSealedClass> the compiler will catch it up.

The problem with this approach is that it does not block some stubborn (or malign) programmer from writing:

class MalignClass : public YourSealedClass, private virtual seal<YourSealedClass> {};

To become a child of the sealing class, and as such gain access to your own class.

In C++0x I believe (would have to recheck it) that they will raise the restriction that a template cannot befriend a template argument, and that will be a good step into a generic typesafe solution for a class sealer:

template <typename T>
class seal {
   friend class T; // illegal in C++03
   seal() {};
   ~seal() {};
};
class MySealedClass : private virtual seal<MySealedClass>
{};

The advantage of this approach (currently unavailable) is that because the constructor and destructors are private only friends can instantiate the type. Because you are using the CRTP to inherit from an specific instantiation passing your own type as argument, you are telling the compiler that only you can actually instantiate your base, and all pieces fall right into place.

这篇关于更简单“防止派生类”在C ++中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆