【问题标题】:C++: Is there a way to limit access to certain methods to certain classes without exposing other private members?C++:有没有办法在不暴露其他私有成员的情况下限制对某些类的某些方法的访问?
【发布时间】:2011-02-23 13:37:45
【问题描述】:

我有一个带有受保护方法 Zig::punt() 的类,我只希望“鳄梨”类可以访问它。在 C++ 中,您通常会使用“friend Avocado”说明符来执行此操作,但这会导致“Avocado”类可以访问所有其他变量;我不想要这个,因为这会破坏封装。

我想要的东西是不可能的,还是已经存在我可以用来实现我想要的东西的晦涩技巧?或者可能实现相同目的的替代类设计模式?

提前感谢您的任何想法!

【问题讨论】:

    标签: c++ methods limit access-modifiers


    【解决方案1】:

    我个人喜欢Key 模式。

    class WannaBeFriend { /**/ };
    
    class WannaBeFriendKey: boost::noncopyable
    {
      friend class WannaBeFriend;
      WannaBeFriendKey () {}
    };
    

    现在:

    class LimitedAccess
    {
    public:
      Item& accessItem(const WannaBeFriendKey&) { return mItem; }
    
    private:
      Item mItem;
      Item mOtherItem;
    };
    

    我真的很喜欢这个解决方案,因为:

    • 你只需要一个前向声明(比如友谊)
    • 您没有友谊授予的完全访问权限,而是在班级编写者的完全控制下授予有限访问权限
    • 此外,可以非常清楚地访问什么以及从谁那里访问,从而简化调试
    • 可以将此访问权限授予WannaBeFriend 的子类:它只需要公开protected: static const WannaBeFriend& Key();(可能适用,也可能不适用)

    当然,编译器很可能会优化此引用的传递,因为它没有任何用途,因此它不会破坏设计,也不会添加不必要的临时:)

    【讨论】:

      【解决方案2】:

      这是一个丑陋但有效的技巧:

      class AvocadoFriender {
      protected:
        virtual void punt() = 0;
        friend class Avocado; 
      }
      
      class Zig : public AvocadoFriender {
        ...
      protected:
        void punt();
      }
      

      基本上,您添加一个 mixin 类,该类仅向 Avocado 公开您想要的接口部分。我们利用了这样一个事实,即通过继承一个与 Avocado 友好的类,除了最初公开的内容之外,您不会再公开任何其他内容。

      【讨论】:

        【解决方案3】:

        您可以向 Zig 类添加代理

        class Foo
        {
            private:
                int m_x, m_y;
            public:
                class Bar
                {
                    friend class Baz;
                    int& x(Foo& blubb)
                    {
                        return blubb.m_x;
                    }
                };
                friend class Bar;
        };
        
        class Baz
        {
            public:
                void grml(Foo& f)
                {
                    Foo::Bar b;
                    // Yes, this looks awful
                    b.x(f) = 42;
                }
        };
        
        void z()
        {
            Foo f;
            Baz b;
            b.grml(f);
        }
        

        【讨论】:

        • 如果您使用原始问题中的相同名称,您的观点可能会更好。 FooBaz 的荒谬程度不亚于 ZigAvocado
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-18
        • 1970-01-01
        • 2021-11-27
        • 1970-01-01
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        相关资源
        最近更新 更多