должны ли вы иметь возможность определять друга внутри класса?

#c

#c

Вопрос:

следующий код отлично компилируется в gcc:

 class vec3
{

private:

  float data[3];

public:

  vec3(float x, float y, float z)
  {
    data[0] = x;
    data[1] = y;
    data[2] = z;
  }

  void operator =(const vec3 amp;v)
  {
    data[0] = v.data[0];
    data[1] = v.data[1];
    data[2] = v.data[2];
  }

  friend vec3 operator *(float a, const vec3 amp;v)
  {
    vec3 res(v.data[0], v.data[1], v.data[2]);
    res.data[0] *= a;
    res.data[1] *= a;
    res.data[2] *= a;
    return res;
  }

};

int main(int argc, char **argv)
{
  vec3 v(1.0, 2.0, 3.0);
  vec3 u = 2*v;
  return 0;
 }
  

кажется, что, хотя оператор * определен внутри класса, он компилируется как функция, не являющаяся членом, потому что он объявлен как friend . это стандартное поведение? это кажется немного странным способом определения функции, не являющейся членом, я не видел такого способа определения друзей, не являющихся членами, ни в каких учебниках / часто задаваемых вопросах (обычно объявляемых внутри класса и определяемых снаружи).

джеймс

Комментарии:

1. ДА. Я ненавижу, когда люди это делают. Из-за этого трудно отличить участников от нечленов. Я предпочитаю определять друга отдельно от класса (и это часть нашего стандарта кодирования). Но это законно.

Ответ №1:

Это стандартно и очень полезно. Даже если дружба не нужна (т. Е. Только потоковая передача общедоступных значений), я часто определяю внутри некоторого класса «X»:

друг std::ostreamamp; operator<<(std::ostreamamp; os, const Xamp; x)
{
 верните os << x.a << " amp; " << x.b; 
}

В вашем примере оператор * должен быть другом для доступа к данным, но не должен быть членом, поскольку значение lhs не является экземпляром класса. Пусть вас не смущает тот факт, что он определен — в отличие от только объявленного — внутри класса. Это ничего не меняет, за исключением того, что функция неявно, как если бы она была квалифицирована как «встроенная» (что является всего лишь подсказкой компилятора и не гарантирует встраивание), избегая проблем с правилом одного определения при множественных включениях.

Комментарии:

1. да, это очень полезно, я просто переношу множество методов из внешних определений внутрь … это делает код читаемым намного лучше и экономит на загрузке объявлений в моем классе 🙂

2. @james edge: Это сарказм?

Ответ №2:

ДА..

В соответствии со стандартными документами, 11.4 Friends - 6

Функция может быть определена в объявлении друга класса тогда и только тогда, когда класс является нелокальным классом (9.8), имя функции не определено и функция имеет область пространства имен.

Пример:

 class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
  

Обратите внимание, что имя функции не определено, и это глобальная функция, которая имеет область действия связанного пространства имен, в котором она определена..

Ответ №3:

Это стандартное поведение, и я видел его по крайней мере один раз в эффективном C .