亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我們能否增加這種面向密鑰的訪問保護模式的可重用性?

我們能否增加這種面向密鑰的訪問保護模式的可重用性?

qq_笑_17 2019-08-19 10:33:03
我們能否增加這種面向密鑰的訪問保護模式的可重用性?我們是否可以增加這種面向密鑰的訪問保護模式的可重用性:class SomeKey {      friend class Foo;     // more friends... ?     SomeKey() {}      // possibly non-copyable too};class Bar {public:     void protectedMethod(SomeKey); // only friends of SomeKey have access};為了避免持續的誤解,這種模式不同于律師 - 客戶的習慣用語:它可以比律師 - 客戶更簡潔(因為它不涉及通過第三類代理)它可以允許授權訪問權限...但它對原始類也更具侵入性(每個方法一個虛擬參數)
查看完整描述

3 回答

?
互換的青春

TA貢獻1797條經驗 獲得超6個贊

我喜歡這個成語,它有可能變得更干凈,更具表現力。


在標準C ++ 03中,我認為以下方式最容易使用且最通用。(但是沒有太大的改進。大多數情況下可以節省自己重復。)因為模板參數不能成為朋友,所以我們必須使用宏來定義passkey:


// define passkey groups

#define EXPAND(pX) pX


#define PASSKEY_1(pKeyname, pFriend1)                             \

        class EXPAND(pKeyname)                                    \

        {                                                         \

        private:                                                  \

            friend EXPAND(pFriend1);                              \

            EXPAND(pKeyname)() {}                                 \

                                                                  \

            EXPAND(pKeyname)(const EXPAND(pKeyname)&);            \

            EXPAND(pKeyname)& operator=(const EXPAND(pKeyname)&); \

        }


#define PASSKEY_2(pKeyname, pFriend1, pFriend2)                   \

        class EXPAND(pKeyname)                                    \

        {                                                         \

        private:                                                  \

            friend EXPAND(pFriend1);                              \

            friend EXPAND(pFriend2);                              \

            EXPAND(pKeyname)() {}                                 \

                                                                  \

            EXPAND(pKeyname)(const EXPAND(pKeyname)&);            \

            EXPAND(pKeyname)& operator=(const EXPAND(pKeyname)&); \

        }

// and so on to some N


//////////////////////////////////////////////////////////

// test!

//////////////////////////////////////////////////////////

struct bar;

struct baz;

struct qux;

void quux(int, double);


struct foo

{

    PASSKEY_1(restricted1_key, struct bar);

    PASSKEY_2(restricted2_key, struct bar, struct baz);

    PASSKEY_1(restricted3_key, void quux(int, double));


    void restricted1(restricted1_key) {}

    void restricted2(restricted2_key) {}

    void restricted3(restricted3_key) {}

} f;


struct bar

{

    void run(void)

    {

        // passkey works

        f.restricted1(foo::restricted1_key());

        f.restricted2(foo::restricted2_key());

    }

};


struct baz

{

    void run(void)

    {

        // cannot create passkey

        /* f.restricted1(foo::restricted1_key()); */


        // passkey works

        f.restricted2(foo::restricted2_key());

    }

};


struct qux

{

    void run(void)

    {

        // cannot create any required passkeys

        /* f.restricted1(foo::restricted1_key()); */

        /* f.restricted2(foo::restricted2_key()); */

    }

};


void quux(int, double)

{

    // passkey words

    f.restricted3(foo::restricted3_key());

}


void corge(void)

{

    // cannot use quux's passkey

    /* 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:

    friend T; // C++0x, MSVC allows as extension

    passkey() {}


    // noncopyable

    passkey(const passkey&) = delete;

    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 

// this by creating a tag and specializing 

// 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, ...)               \

        struct EXPAND(pTag);                             \

                                                         \

        template <>                                      \

        class passkey<EXPAND(pTag)>                      \

        {                                                \

        private:                                         \

            friend pFunc __VA_ARGS__;                    \

            passkey() {}                                 \

                                                         \

            passkey(const passkey&) = delete;            \

            passkey& operator=(const passkey&) = delete; \

        }


// meta function determines if a type 

// is contained in a parameter pack

template<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 passkeys

template <typename... Keys>

class allow

{

public:

    // check if passkey is allowed

    template <typename Key>

    allow(const passkey<Key>&)

    {

        static_assert(is_contained<Key, Keys>::value, 

                        "Passkey is not allowed.");

    }


private:

    // noncopyable

    allow(const allow&) = delete;

    allow& operator=(const allow&) = delete;

};


//////////////////////////////////////////////////////////

// test!

//////////////////////////////////////////////////////////

struct bar;

struct baz;

struct qux;

void quux(int, double);


// make a passkey for quux function

PASSKEY_FUNCTION(quux_tag, void quux(int, double));


struct foo

{    

    void restricted1(allow<bar>) {}

    void restricted2(allow<bar, baz>) {}

    void restricted3(allow<quux_tag>) {}

} f;


struct bar

{

    void run(void)

    {

        // passkey works

        f.restricted1(passkey<bar>());

        f.restricted2(passkey<bar>());

    }

};


struct baz

{

    void run(void)

    {

        // passkey does not work

        /* f.restricted1(passkey<baz>()); */


        // passkey works

        f.restricted2(passkey<baz>());

    }

};


struct qux

{

    void run(void)

    {

        // own passkey does not work,

        // cannot create any required passkeys

        /* f.restricted1(passkey<qux>()); */

        /* f.restricted2(passkey<qux>()); */

        /* f.restricted1(passkey<bar>()); */

        /* f.restricted2(passkey<baz>()); */

    }

};


void quux(int, double)

{

    // passkey words

    f.restricted3(passkey<quux_tag>());

}


void corge(void)

{

    // cannot use quux's passkey

    /* f.restricted3(passkey<quux_tag>()); */

}


int main(){}

僅注意樣板代碼,在大多數情況下(所有非功能情況?。┒疾恍枰貏e定義。該代碼通常簡單地為類和函數的任何組合實現慣用語。


調用者不需要嘗試創建或記住特定于該函數的密鑰。相反,每個類現在都有自己唯一的密碼,函數只需在passkey參數的模板參數中選擇允許的密鑰(不需要額外的定義); 這消除了這兩個缺點。調用者只是創建自己的密鑰并使用它調用,而不需要擔心其他任何事情。


查看完整回答
反對 回復 2019-08-19
  • 3 回答
  • 0 關注
  • 593 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號