сфера дружбы с ++ - PullRequest
       40

сфера дружбы с ++

0 голосов
/ 28 октября 2009

В разделе 11.5.1 «Языка программирования C ++» Бьярн Страуструп пишет:

Как и объявление члена, объявление друга не вводит имя во вложенную область.

Например:

class Matrix
{
    friend class Xform;
    friend Matrix invert (const Matrix &);
//..
 };
Xform x; // error: no Xform in scope
Matrix (*p) (const Matrix &) = &invert; // error: no invert() in scope

Для больших программ и больших классов приятно, что класс не «тихо» добавляет имена в свою объемную область. Для шаблонного класса, который может быть создан во многих различных контекстах (глава 13), это очень важно.

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

Мой вопрос заключается в том, что из-за того, что класс должен быть предварительно определен или определен в области некласса, сразу включающей в себя класс, который объявляет его другом, тогда в первом примере Xform не может быть вне области. предположительно, класс был бы определен до определения класса Matrix. Кроме того, я не могу вспомнить ситуацию, в которой, учитывая ограничение, что класс друга должен быть предварительно определен или определен сразу после класса грантера, что класс друга не будет находиться в области видимости!

Во-вторых, правильна ли моя интерпретация Бьярне в этом разделе:

  • Только для друзей CLASSES, класс друга должен быть предварительно определен во вложенной области, ИЛИ определен сразу после области, не относящейся к классу.
  • Для функции, которая должна была быть ранее объявлена ​​во вложенной области видимости, ИЛИ ее также можно найти с помощью аргумента типа == 'класса дружеского отношения'?

Ответы [ 4 ]

2 голосов
/ 28 октября 2009

Вы правы, что 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, что он подразумевает под этим. Это раздел поиск имени .

1 голос
/ 29 октября 2009

Пример, когда Matrix находится в области видимости, XForm - нет, но есть определенный класс XForm, который является другом Matrix:

1.h
------------------------
namespace Foo
{
 class Matrix
 {
  friend class XForm;
 };
}

1.c
------------------------
#include 1.h
// XForm not in scope
// implement Matrix

2.h
------------------------
namespace Foo
{
 class XForm
 {
 };
}

main.c

#include 1.h
#include 2.h
int main()
{
 // both XForm & Matrix in scope here
}

Это правильно?

0 голосов
/ 28 октября 2009

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

То, что определено как друг, должно быть определено в другом месте, иначе это не друг - это ничто - оно не существует.

Это был вопрос?

0 голосов
/ 28 октября 2009

Я не знаю, понимаю ли я ваш вопрос, но я думаю, что Бьярне подумал, что вам нужно определить класс (скажем, Xform) вне Matrix, если вы хотите его использовать (представьте, что это какой-то вспомогательный класс, который вы добавили в заголовочном файле, который вы не #include во всех .cpp файлах, которые #include файл с Matrix). Вам не нужно определять это, если вы никогда не упоминаете об этом:)

В случае функций ситуация аналогична. Однако есть разница, что его можно определить даже с помощью объявления друга (= внутри класса Matrix) и, как вы говорите, «найти с помощью аргумента типа ==« класса дружеского грантера » (или иметь тип аргумента, который является его вложенным классом), по поиску Кенига.

...