Вы правы, что Xform
нужно было бы определить раньше Matrix
, если пример кода должен был работать . Но это не должно было работать. Это был пример кода bad - код, который пытался заставить объявление друга ввести новые имена в программу, а затем использовать эти имена для объявления переменной и инициализации указателя.
Это был весь автономный пример. Это был не просто отрывок, в котором вы должны были представить дополнительный код до или после данного кода, например определения для Xform
и invert
.
Ваш первый парафраз не совсем корректен. Определение класса друга не обязательно должно сразу следовать за классом, предоставившим ему дружбу. Он должен быть определен в , непосредственно включающей область действия . По сути, он должен быть определен в той же области видимости, что и класс, с которым он дружит. Пример после того, что вы цитируете, иллюстрирует это:
class AE { /* ... */ }; // not a friend of Y
namespace N {
class X { /* ... */ }; // Y's friend
class Y {
friend class X;
friend class Z;
friend class AE;
};
class Z { /* ... */ }; // Y's friend
}
Хотя Y
говорит, что AE
является его другом, он не ссылается на класс AE
, объявленный ранее, поскольку пространство имен N
является непосредственно включающей областью действия Y
, а AE
там не объявлено , Вместо этого объявление друга должно ссылаться на некоторый другой AE
класс, который будет определен в пространстве имен N
в другом месте программы. (Тем не менее, не нужно для определения где-либо вообще; классы могут сказать, что они дружат с вещами, которых не существует, и программе будет все равно. потому что они будут тратить время на поиск нужного AE
класса в исходном коде.)
Вы также ошибаетесь в своем втором парафразе. Функция не должна была быть ранее объявленной в прилагаемой области видимости. Это просто должно быть объявлено в конечном итоге . Рассмотрим пример открытия раздела 11.5, где operator*
указан как друг для Vector
и Matrix
классов до , оператор был либо объявлен, либо определен.
Кроме того, для того, чтобы найти функцию друга, ей не нужно иметь аргументы, равные типу класса. Страуструп говорит, что функция «может быть найдена через ее аргументы», а затем отсылает вас к разделу 8.2.6, что он подразумевает под этим. Это раздел поиск имени .