Хорошо - если вы хотите именно то, что вы описали, тогда друг - лучшее решение. Каждый стандарт кодирования рекомендует не использовать friend , но там, где альтернативный дизайн более сложный - тогда, возможно, стоит сделать исключение.
Для решения проблемы без друга потребуется другая архитектура
Одним из решений может быть использование формы pImpl idiom , где «B» происходит от внутреннего объекта реализации, в то время как другие клиенты происходят от внешнего класса.
Другим может быть размещение дополнительного уровня наследования между «A» и «другими клиентами». Что-то вроде:
class A {
public:
void foo ();
void bar ();
};
class B : public A { // OK access to both 'foo' and 'bar'
};
class ARestricted : private A {
public:
inline void foo () { A::foo (); }; // Forwards 'foo' only
};
Однако, у этого решения все еще есть свои проблемы. «ARestricted» не может преобразовать в «A», так что это должно быть решено другим «получателем» для «A». Однако вы можете назвать эту функцию так, чтобы ее нельзя было вызвать случайно:
inline A & get_base_type_A_for_interface_usage_only () { return *this; }
После попытки подумать о других решениях и предположив, что ваша иерархия должна быть такой, как вы описали, я рекомендую вам просто использовать друг !
РЕДАКТИРОВАТЬ: Итак xtofl предложил переименовать типы «A» в «AInternal» и «ARestricted» в «A».
Это работает, за исключением того, что я заметил, что «B» больше не будет «A». Тем не менее, AInternal может быть унаследован виртуально - и тогда «B» может происходить как от «AInternal», так и от «A»!
class AInternal {
public:
void foo ();
void bar ();
};
class A : private virtual AInternal {
public:
inline void foo () { A::foo (); }; // Forwards 'foo' only
};
// OK access to both 'foo' and 'bar' via AInternal
class B : public virtual AInternal, public A {
public:
void useMembers ()
{
AInternal::foo ();
AInternal::bar ();
}
};
void func (A const &);
int main ()
{
A a;
func (a);
B b;
func (b);
}
Конечно, теперь у вас есть виртуальные базы и множественное наследование! Хммм .... теперь, это лучше или хуже, чем одна друг декларация?