Интересный пример, когда определение friend T
(где T
— шаблонный параметр) имеет смысл:
template <class T>
class Badge {
friend T;
Badge() { }
};
Допустим, у нас есть какой-нибудь публичный метод, и предполагается, что круг его пользователей ограничен одним классом, например:
class VFS {
...
public:
void register_device(Device&);
void unregister_device(Device&);
};
Предполагается, что эти методы будут вызываться внутри конструкторов (и деструкторов) Device
и нигде (и никем) больше. Но как закрепить наше ожидание на уровне API?
Распространенное решение — вынести (un)register_device
в приватную часть, а Device
объявить другом:
class VFS {
private:
friend class Device;
void register_device(Device&);
void unregister_device(Device&);
};
И это действительно запрещает всем кроме Device
обращаться к данным методам. Но это так же разрешает Device
обращаться ко всем остальным членам VFS
!
Выразить же желаемое наиболее четко и ясно нам помогает как раз таки класс Badge
, приведенный в самом начале статьи: мы можем оставить методы (un)register_device
публичными, но при этом сделать их первым аргументом значение Badge<Device>
:
class VFS {
...
public:
void reg_Device(Badge<Device>, Device&);
void unregister_device(Badge<Device>, Device&);
};
Теперь чужак не может использовать эти методы, потому что он не может сконструировать Badge<Device>
, а а сам Device
может вызывать их где и как пожелает:
Device::Device()
{
VFS::instance().register_device({}, *this);
}