friend T (где T — шаблонный параметр) имеет смысл:template <typename 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 register_device(Badge<Device>, Device&);
void unregister_device(Badge<Device>, Device&);
};Теперь чужак не может использовать эти методы, потому что он не может сконструировать
Badge<Device> (его конструктор приватный и доступен только Device), а сам Device может вызывать их где и как пожелает:Device::Device()
{
VFS::instance().register_device({}, *this);
}

