Объявите функцию-член заранее объявленного класса как друга - PullRequest
12 голосов
/ 10 июня 2011

Можно ли объявить функцию-член заранее объявленного класса как друга? Я пытаюсь сделать следующее:

class BigComplicatedClass;

class Storage {
   int data_;
public:
   int data() { return data_; }
   // OK, but provides too broad access:
   friend class BigComplicatedClass;
   // ERROR "invalid use of incomplete type":
   friend void BigComplicatedClass::ModifyStorage(); 
};

Таким образом, цель состоит в том, чтобы (i) ограничить объявление друга одним методом и (ii) не включать определение сложного класса для сокращения времени компиляции.

Одним из подходов может быть добавление класса, выступающего в качестве посредника:

// In Storage.h:
class BigComplicatedClass_Helper;
class Storage {
    // (...)
    friend class BigComplicatedClass_Helper;
};

// In BigComplicatedClass.h:
class BigComplicatedClass_Helper {
     static int &AccessData(Storage &storage) { return storage.data_; }
     friend void BigComplicatedClass::ModifyStorage();
};

Однако это кажется немного неуклюжим ... поэтому я предполагаю, что должно быть лучшее решение!

Ответы [ 3 ]

12 голосов
/ 10 июня 2011

Как говорит @Ben, это невозможно, но вы можете предоставить конкретный доступ только к этой функции-члену через «ключ доступа» . Он работает немного как промежуточный вспомогательный класс, но imho более понятен:

// Storage.h
// forward declare the passkey
class StorageDataKey;

class Storage {
   int data_;
public:
   int data() { return data_; }
   // only functions that can pass the key to this function have access
   // and get the data as a reference
   int& data(StorageDataKey const&){ return data_; }
};

// BigComplicatedClass.cpp
#include "BigComplicatedClass.h"
#include "Storage.h"

// define the passkey
class StorageDataKey{
  StorageDataKey(){} // default ctor private
  StorageDataKey(const StorageDataKey&){} // copy ctor private

  // grant access to one method
  friend void BigComplicatedClass::ModifyStorage();
};

void BigComplicatedClass::ModifyStorage(){
  int& data = storage_.data(StorageDataKey());
  // ...
}
3 голосов
/ 10 июня 2011

Нет, вы не можете объявить отдельные функции-члены как друзья, пока они не были объявлены.Вы можете подружиться только со всем классом.

1 голос
/ 07 февраля 2013

Это может быть или не быть уместным здесь, но полезно напомнить себе, что существует дикий мир, выходящий за рамки классов и объектов, где функции могут свободно перемещаться.

Например, недавно я нуждался взакрыть (единый глобальный статический) системный журнал ошибок из глобального обработчика исключений на основе порта чужого кода.Обычный включаемый файл для моего журнала ошибок конфликтовал с кодом обработчика исключений, потому что оба хотели включить «windows.h» по причинам, которые я не изучал.Когда этот и другие вопросы убедили меня, я не смог сделать предварительное объявление функций-членов моего класса ErrorLog, я сделал так, что обернул необходимые функции в глобальную функцию области видимости:

void WriteUrgentMessageToErrorLog( const char * message )
{
  ErrorLog::LogSimpleMessage( message );
  ErrorLog::FlushAccumulatedMessagesToDisk();
}

Некоторые люди оченьособенно о поддержании целостности структуры их классов любой ценой ... и редко признают, что приложения, использующие эти классы, неизбежно создаются поверх чего-то, что не имеет такой структуры.Но он там и используется разумно, у него есть свое место.

Учитывая возраст этого вопроса, я не стал подробно изучать его актуальность.Все, что я хотел поделиться, - это мнение, что иногда такой простой механизм обертывания является гораздо более чистой и понятной альтернативой чему-то, что имеет гораздо больше тонкости и хитрости.Тонкость и сообразительность имеют тенденцию меняться в более поздние сроки кем-то, кто должен добавить к этому, кто не полностью понимает это.Прежде чем вы это знаете, у вас есть ошибка ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...