我们能否增加这种面向密钥的访问保护模式的可重用性?

我们能否增加这种面向密钥的访问保护模式的可重用性?

我们是否可以增加这种面向密钥的访问保护模式的可重用性:

class SomeKey { 
    friend class Foo;
    // more friends... ?
    SomeKey() {} 
    // possibly non-copyable too};class Bar {public:
    void protectedMethod(SomeKey); // only friends of SomeKey have access};

为了避免持续的误解,这种模式不同于律师 - 客户的习惯用语:

  • 它可以比律师 - 客户更简洁(因为它不涉及通过第三类代理)

  • 它可以允许授权访问权限

  • ...但它对原始类也更具侵入性(每个方法一个虚拟参数)


qq_笑_17
浏览 505回答 3
3回答

互换的青春

我喜欢这个成语,它有可能变得更干净,更具表现力。在标准C ++ 03中,我认为以下方式最容易使用且最通用。(但是没有太大的改进。大多数情况下可以节省自己重复。)因为模板参数不能成为朋友,所以我们必须使用宏来定义passkey:// define passkey groups#define EXPAND(pX) pX#define PASSKEY_1(pKeyname, pFriend1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; class EXPAND(pKeyname)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; private:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; friend EXPAND(pFriend1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EXPAND(pKeyname)() {}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EXPAND(pKeyname)(const EXPAND(pKeyname)&);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EXPAND(pKeyname)& operator=(const EXPAND(pKeyname)&); \&nbsp; &nbsp; &nbsp; &nbsp; }#define PASSKEY_2(pKeyname, pFriend1, pFriend2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; class EXPAND(pKeyname)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; private:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; friend EXPAND(pFriend1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; friend EXPAND(pFriend2);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EXPAND(pKeyname)() {}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EXPAND(pKeyname)(const EXPAND(pKeyname)&);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EXPAND(pKeyname)& operator=(const EXPAND(pKeyname)&); \&nbsp; &nbsp; &nbsp; &nbsp; }// and so on to some N//////////////////////////////////////////////////////////// test!//////////////////////////////////////////////////////////struct bar;struct baz;struct qux;void quux(int, double);struct foo{&nbsp; &nbsp; PASSKEY_1(restricted1_key, struct bar);&nbsp; &nbsp; PASSKEY_2(restricted2_key, struct bar, struct baz);&nbsp; &nbsp; PASSKEY_1(restricted3_key, void quux(int, double));&nbsp; &nbsp; void restricted1(restricted1_key) {}&nbsp; &nbsp; void restricted2(restricted2_key) {}&nbsp; &nbsp; void restricted3(restricted3_key) {}} f;struct bar{&nbsp; &nbsp; void run(void)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // passkey works&nbsp; &nbsp; &nbsp; &nbsp; f.restricted1(foo::restricted1_key());&nbsp; &nbsp; &nbsp; &nbsp; f.restricted2(foo::restricted2_key());&nbsp; &nbsp; }};struct baz{&nbsp; &nbsp; void run(void)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // cannot create passkey&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted1(foo::restricted1_key()); */&nbsp; &nbsp; &nbsp; &nbsp; // passkey works&nbsp; &nbsp; &nbsp; &nbsp; f.restricted2(foo::restricted2_key());&nbsp; &nbsp; }};struct qux{&nbsp; &nbsp; void run(void)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // cannot create any required passkeys&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted1(foo::restricted1_key()); */&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted2(foo::restricted2_key()); */&nbsp; &nbsp; }};void quux(int, double){&nbsp; &nbsp; // passkey words&nbsp; &nbsp; f.restricted3(foo::restricted3_key());}void corge(void){&nbsp; &nbsp; // cannot use quux's passkey&nbsp; &nbsp; /* f.restricted3(foo::restricted3_key()); */}int main(){}此方法有两个缺点:1)调用者必须知道它需要创建的特定密钥。虽然简单的命名方案(function_key)基本上消除了它,但它仍然可以是一个抽象清洁器(并且更容易)。2)虽然使用宏并不是很困难,但可能会看起来有点难看,需要一组passkey-definitions。但是,在C ++ 03中无法对这些缺点进行改进。在C ++ 0x中,成语可以达到其最简单,最具表现力的形式。这是由于可变参数模板和允许模板参数成为朋友。(请注意,2010年之前的MSVC允许模板专家说明符作为扩展;因此可以模拟此解决方案):// each class has its own unique key only it can create// (it will try to get friendship by "showing" its passkey)template <typename T>class passkey{private:&nbsp; &nbsp; friend T; // C++0x, MSVC allows as extension&nbsp; &nbsp; passkey() {}&nbsp; &nbsp; // noncopyable&nbsp; &nbsp; passkey(const passkey&) = delete;&nbsp; &nbsp; passkey& operator=(const passkey&) = delete;};// functions still require a macro. this// is because a friend function requires// the entire declaration, which is not// just a type, but a name as well. we do&nbsp;// this by creating a tag and specializing&nbsp;// the passkey for it, friending the function#define EXPAND(pX) pX// we use variadic macro parameters to allow// functions with commas, it all gets pasted// back together again when we friend it#define PASSKEY_FUNCTION(pTag, pFunc, ...)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; struct EXPAND(pTag);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; template <>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; class passkey<EXPAND(pTag)>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; private:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; friend pFunc __VA_ARGS__;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; passkey() {}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; passkey(const passkey&) = delete;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; passkey& operator=(const passkey&) = delete; \&nbsp; &nbsp; &nbsp; &nbsp; }// meta function determines if a type&nbsp;// is contained in a parameter packtemplate<typename T, typename... List>struct is_contained : std::false_type {};template<typename T, typename... List>struct is_contained<T, T, List...> : std::true_type {};template<typename T, typename Head, typename... List>struct is_contained<T, Head, List...> : is_contained<T, List...> {};// this class can only be created with allowed passkeystemplate <typename... Keys>class allow{public:&nbsp; &nbsp; // check if passkey is allowed&nbsp; &nbsp; template <typename Key>&nbsp; &nbsp; allow(const passkey<Key>&)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; static_assert(is_contained<Key, Keys>::value,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Passkey is not allowed.");&nbsp; &nbsp; }private:&nbsp; &nbsp; // noncopyable&nbsp; &nbsp; allow(const allow&) = delete;&nbsp; &nbsp; allow& operator=(const allow&) = delete;};//////////////////////////////////////////////////////////// test!//////////////////////////////////////////////////////////struct bar;struct baz;struct qux;void quux(int, double);// make a passkey for quux functionPASSKEY_FUNCTION(quux_tag, void quux(int, double));struct foo{&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; void restricted1(allow<bar>) {}&nbsp; &nbsp; void restricted2(allow<bar, baz>) {}&nbsp; &nbsp; void restricted3(allow<quux_tag>) {}} f;struct bar{&nbsp; &nbsp; void run(void)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // passkey works&nbsp; &nbsp; &nbsp; &nbsp; f.restricted1(passkey<bar>());&nbsp; &nbsp; &nbsp; &nbsp; f.restricted2(passkey<bar>());&nbsp; &nbsp; }};struct baz{&nbsp; &nbsp; void run(void)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // passkey does not work&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted1(passkey<baz>()); */&nbsp; &nbsp; &nbsp; &nbsp; // passkey works&nbsp; &nbsp; &nbsp; &nbsp; f.restricted2(passkey<baz>());&nbsp; &nbsp; }};struct qux{&nbsp; &nbsp; void run(void)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // own passkey does not work,&nbsp; &nbsp; &nbsp; &nbsp; // cannot create any required passkeys&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted1(passkey<qux>()); */&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted2(passkey<qux>()); */&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted1(passkey<bar>()); */&nbsp; &nbsp; &nbsp; &nbsp; /* f.restricted2(passkey<baz>()); */&nbsp; &nbsp; }};void quux(int, double){&nbsp; &nbsp; // passkey words&nbsp; &nbsp; f.restricted3(passkey<quux_tag>());}void corge(void){&nbsp; &nbsp; // cannot use quux's passkey&nbsp; &nbsp; /* f.restricted3(passkey<quux_tag>()); */}int main(){}仅注意样板代码,在大多数情况下(所有非功能情况!)都不需要特别定义。该代码通常简单地为类和函数的任何组合实现惯用语。调用者不需要尝试创建或记住特定于该函数的密钥。相反,每个类现在都有自己唯一的密码,函数只需在passkey参数的模板参数中选择允许的密钥(不需要额外的定义); 这消除了这两个缺点。调用者只是创建自己的密钥并使用它调用,而不需要担心其他任何事情。
打开App,查看更多内容
随时随地看视频慕课网APP