Можно ли написать оператор автозапуска вне структуры?

Точная ситуация следующая: Я определил в системных API-структурах CGPoint и CGSize, и я хочу иметь возможность писать my_point = my_size. Я не могу изменить структуру CGPoint, но может писать внешний оператор. Я могу написать двоичные операторы (+, -,...), но operator= должен быть объявлен внутри структуры. Итак, есть ли другое решение?

Ответы

Ответ 1

Чтобы скомпилировать выражение a = b;, вам нужно либо иметь operator= в типе a, который принимает элемент типа b, либо тип, неявно конвертируемый из b.

Первый случай исключается, так как operator= должен быть членом класса, и поскольку вы не можете изменить GLPoint, вы не можете добавить GLPoint& GLPoint::operator=( GLSize ).

Второй случай страдает от того же типа проблем. Неявное преобразование из GLSize в GLPoint может быть реализовано как неявный конструктор в GLPoint (исключен) или как член operator GLPoint() в GLSize, что требует модификации GLSize. Конверсии также не могут быть добавлены как свободные функции.

Альтернативы используют синтаксис без оператора, добавляя свободную функцию assign (или copy): GLPoint& assign( GLPoint&, GLSize const & ).

Следующий вопрос - почему вы хотите это сделать. Если дизайнеры GLPoint и GLSize не считали, что размер должен быть назначен для точки, то почему вы чувствуете, что они должны быть назначаемыми? В общем, рекомендуется сохранять типы отдельно, поскольку это позволит компилятору обнаруживать ошибки, которые могут возникнуть в вашем коде.

Если вы разрешаете неявные преобразования от GLSize до GLPoint, вы можете по ошибке ввести что-то вроде: distance( point1, size2 ), где вы имели в виду distance( point1, point2 ), а поскольку есть преобразование, компилятор с радостью будет конвертировать и применять. Затем вы увидите странные результаты, и вы проведете немало приятных отладочных часов, пытаясь определить, где логика неправильная.

Если у домена нет четкого определения того, что означает каждый оператор в этом контексте, я бы избегал перегрузки оператора любой ценой. Будут ли все, кто читает ваш код, сразу понять, что GLPoint(1,2) + GLSize(5) представляет без сомнения или двусмысленности? Если это не так, если люди будут удивлены или даже сомневаются, то избегайте перегрузки оператора и используйте именованные функции: move_up( GLPoint&, GLSize ) (или любой другой размер + размер означает для вас)

Ответ 2

Когда вы назначаете CGSize в CGPoint - что происходит? Переопределите это на некоторый оператор и там у вас есть - например

CGPoint& operator|=(CGPoint& cPoint, CGSize const& cSize)
{
  // now set attributes of cPoint that you can extract from cSize

  return cPoint;
}

Что так сложно? Вот пример: http://www.ideone.com/FZN20

Ответ 3

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

Ответ 4

Другие ответы швы, чтобы пропустить очевидное решение: добавьте функцию для преобразования CGPoint в CGSize. Конечно, это не совсем то, что вы хотите (size = point), но поскольку вы не можете изменить один из двух классов, это единственный способ:

CGSize ToSize( const CGPoint &pt )
{
  CGSize res = ...
  // do the conversion
  return res;
}