2016-01-02 3 views
7

Скажем, я хочу, чтобы переопределить operator =, так что я могу сделать что-то вродеПочему оператор = возвращает * это?

Poly p1; // an object representing a polynomial 
Poly p2; // another object of the same type  
p2 = p1; // assigns all the contents of p1 to p2 

Тогда в моей реализации operator =, у меня есть что-то вроде этого:

Poly& Poly::operator=(const Poly &source) { 
    // Skipping implementation, it already works fine… 
    return *this; 
} 

Не возражаете реализации, он уже работает отлично.

Мое беспокойство заключается в том, что происходит, когда вы return *this? Я знаю, что он возвращает ссылку на объект, но так ли это происходит?

p2 = &p1 
+1

Поскольку 'Я просто новичок в C++' часть была утрачена в (в противном случае хорошо означало) редактирование, а так как вариации 'p2 = & p1' всплывают в комментариях ...' '' 'и' 'в' Poly & Poly :: operator = 'объявление означает, что оператор возвращает ссылку - для себя в этом случае, что точно что 'return * this,' делает.С другой стороны, '&' in '& p1' оценивает адрес' p1', который является указателем 'Poly *' и не может быть назначен объекту 'Poly'. Не путайте два значения '&' в двух разных контекстах. – dxiv

ответ

13

Вы return *this, так что вы можете написать нормальное соединение C++ = заявления вроде:

Poly p1; //an object representing a polynomial 
Poly p2; 
Poly p2; 

// ... 

p3 = p2 = p1; //assigns all the contents of p1 to p2 and then to p3 

, потому что утверждение в основном:

p3.operator=(p2.operator=(p1)); 

Если p2.operator=(...) не return *this вы бы ничего значимого, чтобы перейти в p3.operator=(...).

+0

да, я это знаю. Но я беспокоюсь, что происходит, когда вы возвращаете это? Я имею в виду, основываясь на вашем примере, работает ли это так? p3 = p2 = &p1; p3 = &p2; –

+0

@JudeMaranga Отредактированный ответ соответственно. Вы не хотите принимать адрес, например 'p1' (* i.e. *' & p1'), 'operator =' принимает 'const Poly & source', поэтому' * this' дает вам это. –

+0

Я получаю то, что вы пытаетесь сказать там. но после p3.operator = (...) return * this, кто будет ловить эту возвращаемую стоимость? –

5

p2 = p1 является сокращением на p2.operator=(p1). Он просто вызывает вашу функцию operator=, которая возвращает ссылку на p2, которую вы игнорируете. Чтобы пояснить это, давайте назовем его assign вместо operator=:

Poly& Poly::assign(const Poly &source) { 
    . 
    . 
    . 
    return *this; 
} 

Теперь вместо p2 = p1, можно было бы написать

p2.assign(p1); 

В этом случае результат вызова assign игнорируется, но вы не стоит его игнорировать. Например, вы могли бы написать:

p3.assign(p2.assign(p1)); 

Использование operator= вместо assign, это становится

p3 = (p2 = p1); 

, но так как назначение правоассоциативное, это также может быть записано в виде

p3 = p2 = p1; 

Эта форма выполнения нескольких заданий сразу изначально происходит от C и была сохранена на C++ по соглашению о возврате *this в operator=().

+0

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

+0

@JudeMaranga: Я расширил свой ответ, чтобы помочь объяснить. –

+0

@ChristianHackl: Я сделал небольшое редактирование. Спасибо, что сообщили мне, что случилось. –

0

Возвращение ссылки на целевой объект позволяет присваивания цепочки (каскадный), и перегрузка операторов в пределах класса следующим правоассоциативной (нажмите here для детального оператора перегрузки правил)

Poly a, b, c; 
a = b = c; 
4

Может возникнуть соблазн сделать оператор присваивания копий возвращает void, если вам не понадобятся прикованные присваивания (как показано в других ответах) в любом случае. В конце концов, прикомандированные задания часто трудно читать и понимать, поэтому их нельзя считать улучшением .

Однако часто упускается из виду, что void operator=(Poly& const) означает, что ваш тип больше не будет соответствовать CopyAssignable concept, для чего требуется тип возврата T&.

типа, который не выполняет CopyAssignable понятия не может быть официально использоваться для некоторых стандартных контейнеров операций, например std::vector::insert, что означает, что следующий, казалось бы, невинный кусок кода доходности неопределенного поведения, несмотря на то, что, вероятно, работает прекрасно:

#include <vector> 

struct Poly 
{ 
    void operator=(Poly const&) {} // Poly is not CopyAssignable 
}; 

int main() 
{ 
    std::vector<Poly> v; 
    Poly p; 
    v.insert(v.begin(), p); // undefined behaviour 
} 

в стандартном с ++ объясняет в § 17.6.4.8/2.3, где говорится об ограничениях на программах с использованием стандартной библиотеки:

(...) эффекты являются неопределенные в следующих случаях:

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

Конечно, это именно потому, что на неопределенное поведение, что компилятор позволено игнорировать ошибку и сделать программу ведут себя хорошо, соответствуя явно предназначенное поведение. Но этого не требуется.

Вы также должны учитывать, что вы не можете предсказать все будущие использования вашего типа Poly. Кто-то может написать какой-нибудь шаблон функции, такие как:

template <class T> 
void f(T const& t) 
{ 
    T t2; 
    T t3 = t2 = t; 
    // ... 
} 

Эта функция будет потом не работать с Poly класса.

Просто не нарушайте это соглашение C++, и вы не столкнетесь с проблемами.

2

что происходит, когда вы возвращаете * это?

В вашем примере (p2 = p1;) ничего. Метод копирует p1 в p2 и возвращает ссылку на объект «this», который код вызова не использует.

В коде, такие как p3 = p2 = p1;, первый вызов является p2 = p1, который копирует p1 в p2 и возвращает ссылку на p2. Затем вызывающий код копирует с этой ссылки на p2 в p3 (и игнорирует ссылку на p3, которая возвращается).

(Попутно:! Сделать ваши модульные тесты убедитесь, что p1 = p1 работает должным образом, легко забыть тот случай)

+1

Если вы правильно выполняете оператор, используя идиому копирования и свопинга, вам вообще не нужно обрабатывать самоназначение. Действительно, 'if (this! = & Other)' часто является индикатором опасного кода. Исключение может быть сделано для редких проблем оптимизации. –

Смежные вопросы