C ++: Есть ли способ ограничить доступ к определенным методам для определенных классов, не подвергая других закрытых членов? - PullRequest
3 голосов
/ 25 мая 2010

У меня есть класс с защищенным методом Zig :: punt (), и я только хочу, чтобы он был доступен для класса "Авокадо". В C ++ вы обычно делаете это, используя спецификатор "Друг Авокадо", но это приведет к тому, что все остальные переменные станут доступны для класса "Авокадо"; Я не хочу этого, потому что это нарушает инкапсуляцию.

Является ли то, что я хочу, невозможным или уже существует неясная уловка, которую я могу использовать для достижения того, чего хочу? Или, возможно, альтернативные шаблоны проектирования классов, которые достигнут того же самого?

Заранее спасибо за любые идеи!

Ответы [ 3 ]

4 голосов
/ 25 мая 2010

Вот ужасный, но работающий трюк:

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

class Zig : public AvocadoFriender {
  ...
protected:
  void punt();
}

По сути, вы добавляете класс mixin, который предоставляет только ту часть интерфейса, которую вы хотите использовать в Avocado. Мы пользуемся тем фактом, что, наследуя класс, который подружился с Avocado, вы не раскрываете ничего больше, кроме того, что было открыто изначально.

3 голосов
/ 25 мая 2010

Мне лично нравится шаблон 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(); (может применяться или не применяться)

И, конечно, очень вероятно, что компилятор оптимизирует передачу этой ссылки, поскольку он не служит какой-либо цели, поэтому он не портит дизайн и не добавляет ненужных временных файлов:)

0 голосов
/ 25 мая 2010

Вы можете добавить прокси к классу 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);
}
...