时间:2010-07-24 11:27:02

标签: c++ design-patterns idioms friend access-protection

3 个答案:

答案 0 :(得分:25)

答案 1 :(得分:1)

我读过很多关于不可复制性的评论。许多人认为它不应该是不可复制的,因为我们不能将它作为参数传递给需要密钥的函数。有些人甚至对此感到惊讶。好吧它真的不应该,并且显然与一些Visual C ++编译器有关,因为我之前有相同的怪异但不再使用Visual C ++ 12(Studio 2013)。

但事实上,我们可以通过“基本”不可复制性来增强安全性。 Boost版本太多了,因为它完全阻止了复制构造函数的使用,因此对于我们需要的东西来说有点太多了。我们需要的是实际上将复制构造函数设为私有但不是没有实现。当然,实现将是空的,但它必须存在。我最近问过在这种情况下谁在调用copy-ctor(在这种情况下,在调用SomeKey时调用了ProtectedMethod的复制构造函数)。答案是,显然标准确保调用-ctor的方法调用者确实看起来很合乎逻辑。因此,通过copy-ctor隐私,我们允许朋友发挥作用(protected Bargranted Foo)来调用它,从而允许Foo调用ProtectedMethod因为它使用值参数传递,但它也阻止任何人超出Foo的范围。

通过这样做,即使同事开发人员尝试使用代码聪明地玩,他实际上必须让Foo完成工作,另一个类将无法获得密钥,并且机会很多他几乎100%的时间都会以这种方式认识到他的错误(希望,否则他太过于初学者使用这种模式,或者他应该停止开发:P)。

答案 2 :(得分:1)

来自@GManNickG的精彩回答。学到了很多东西。试图让它工作,发现了一些错别字。为清楚起见,重复完整示例我的例子借用了#34;包含Key in Keys ..." @snk_kid发布的Check if C++0x parameter pack contains a type函数。

#include<type_traits>
#include<iostream>

// identify if type is in a parameter pack or not
template < typename Tp, typename... List >
struct contains : std::false_type {};

template < typename Tp, typename Head, typename... Rest >
struct contains<Tp, Head, Rest...> :
  std::conditional< std::is_same<Tp, Head>::value,
  std::true_type,
  contains<Tp, Rest...>
  >::type{};

template < typename Tp >
struct contains<Tp> : std::false_type{};


// everything is private!
template <typename T>
class passkey {
private:
  friend T;
  passkey() {}

  // noncopyable
  passkey(const passkey&) = delete;
  passkey& operator=(const passkey&) = delete;
};


// what keys are allowed
template <typename... Keys>
class allow {
public:
  template <typename Key>
  allow(const passkey<Key>&) {
    static_assert(contains<Key, Keys...>::value, "Pass key is not allowed");
  }

private:
  // noncopyable
  allow(const allow&) = delete;
  allow& operator=(const allow&) = delete;
};


struct for1;
struct for2;

struct foo {
  void restrict1(allow<for1>) {}
  void restrict2(allow<for1, for2>){}
} foo1;
struct for1 {
  void myFnc() {
    foo1.restrict1(passkey<for1>());
  }
};
struct for2 {
  void myFnc() {
    foo1.restrict2(passkey<for2>());
   // foo1.restrict1(passkey<for2>()); // no passkey
  }
};


void main() {
  std::cout << contains<int, int>::value << std::endl;
  std::cout << contains<int>::value << std::endl;
  std::cout << contains<int, double, bool, unsigned int>::value << std::endl;
  std::cout << contains<int, double>::value << std::endl;
}