【问题标题】:C++: Allowing Access to Protected Members of Class and not Private MembersC++:允许访问受保护的类成员而不是私有成员
【发布时间】:2012-05-03 20:48:02
【问题描述】:

我知道您可以通过继承来做到这一点,但您应该使用继承,除非是“是”情况。我也知道有朋友,但他们也允许访问私人成员。

有没有办法做到这一点(允许访问受保护的类成员而不是私有成员)?

为了改写这个问题,我有 1 类和 2 类。我希望 2 类可以访问 1 类的受保护成员和公共成员,但不能访问私有成员。我该怎么做?

【问题讨论】:

  • 这是什么this你在Is there any way of doing this?中引用
  • 我应该更清楚。我指的是这个问题:“允许访问受保护的类成员而不是私人成员”
  • 至于允许访问谁,我指的是第一类。

标签: c++ class


【解决方案1】:

很久以前,在这个网站上,我提出了一个使用Key 的方案。这个想法是主类记录接口的哪些部分可以公开访问,哪些需要密钥,然后将与密钥的友谊授予需要它的人。

class Key { friend class Stranger; Key() {} ~Key() {} };

class Item {
public:
    void everyone();

    void restricted(Key);
private:
};

现在,只有Stranger 可以使用restricted 方法,如下所示:

class Stranger {
public:
    void test(Item& i) {
        Key k;
        i.restricted(k);
    }

    Key key() { return Key(); }

    Key _key;
};

class Other {
    void test(Item& i) {
        Stranger s;
        i.restricted(s.key()); // error: ‘Key::~Key()’ is private
                               // error: within this context
    }

    void test2(Item& i) {
        Stranger s;
        i.restricted(s._key); // error: ‘Key::~Key()’ is private
                              // error: within this context
                              // error:   initializing argument 1 of ‘void Item::restricted(Key)’
    }
};

这是一个非常简单的方案,它允许使用更细粒度的方法来获得完整的友谊。

【讨论】:

    【解决方案2】:

    Oli 提供了一个更接近的解决方案 (+1),但您也可以使用选择性朋友来接近它:

    #include <iostream>
    
    class t_thing;
    
    class t_elsewhere {
    public:
        void print(const t_thing& thing);
    };
    
    class t_thing {
    public:
        class t_selective_friend {
            static int Prot(const t_thing& thing) {
                return thing.prot;
            }
    
            friend class t_elsewhere;
        };
    public:
        int publ;
    protected:
        int prot;
    protected:
        int priv;
    };
    
    void t_elsewhere::print(const t_thing& thing) {
        std::cout << t_thing::t_selective_friend::Prot(thing) << std::endl;
    }
    
    int main() {
        t_thing thing;
    
        thing.publ; /* << ok */
        thing.prot; /* << error */
        thing.priv; /* << error */
        t_elsewhere().print(thing); /* << ok */
        return 0;
    }
    

    有时冗长/控制是好的……

    【讨论】:

      【解决方案3】:

      这并不优雅,但这可能对你有用:

      class B;
      
      class A {
      protected:
          int x;
      private:
          int y;
      };
      
      class A_wrapper : public A {
          friend B;
      };
      
      
      class B {
      public:
          A_wrapper a;
          int foo() {
              a.x;   // Ok
              a.y;   // Compiler error!
          }
      };
      

      【讨论】:

      • 把东西弄干净确实很棘手。 protected 适用于基类子对象的成员,但不适用于相同类型的其他对象的成员。 (即仅通过this)
      • @OliCharlesworth 但您认为这样做是个好主意吗?不是你的实现,而是总体思路。
      • 这看起来是最干净和最简单的方法,所以我会从周围的一些 cmets 中接受它,我想我可能会尝试通过移动其他一些变量来让它工作,所以我不必。
      • @juanchopanza:我想这取决于具体情况。如果需要这样做,这可能表明需要重新设计(尽管并不总是那么奢侈!)。
      • 语言阻止你做某事并不意味着它是设计问题。这也可能是语言限制。例如,“朋友”是全有或全无。您不能仅授予访问您私人/受保护内容的一部分的权限。是的,你可以绕过这个,例如通过将一个类分成两个或多个部分。从工程的角度来看,这似乎是一种“更清洁”的方式,但这提供了很多样板代码。如果你有太多的样板,那么无论从工程的角度来看它看起来多么正确,它都会变得难以使用。
      猜你喜欢
      • 2016-07-15
      • 1970-01-01
      • 1970-01-01
      • 2013-02-13
      • 2017-08-01
      • 2016-10-01
      • 2023-03-03
      • 2016-05-22
      相关资源
      最近更新 更多