2016-05-02 3 views
3

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

Кроме того, может кто-нибудь сказать мне, почему конструктор копирования вызывается каждый раз, когда я возвращаю * это или объект типа Rectangle из любого из моих перегруженных операторов?

class Rectangle 
{ 
    private: 
     int length; 
     int width; 
     static int counter; 
    public: 
     Rectangle(int len = 0, int w = 0) 
     { 
      length = len; 
      width = w; 
      counter++; 
     } 
     ~Rectangle() 
      { counter--; } 
     static int getCounter() 
      { return counter; } 

     Rectangle(const Rectangle &); 
     Rectangle operator+ (const Rectangle &); 
     Rectangle operator= (const Rectangle &); 
}; 

int Rectangle::counter = 0; 

Rectangle::Rectangle(const Rectangle &right) : Rectangle() 
{ 
    width = right.width; 
    length = right.length; 
} 

Rectangle Rectangle::operator+ (const Rectangle &right) 
{ 
    width += right.width; 
    length += right.length; 
    return *this; 
} 

Rectangle Rectangle::operator= (const Rectangle &right) 
{ 
    width = right.width; 
    length = right.length; 
    return *this; 
} 
+0

': Rectangle()' неверно в определении конструктора. –

+0

В любом случае я мог бы правильно увеличить счетчик? Если я использую конструктор копирования, чтобы сделать один объект равным другому, он не будет ссылаться на конструктор по умолчанию и, следовательно, не будет увеличивать счетчик. –

+0

Увеличение счетчика в каждом определении конструктора. –

ответ

-1

Кроме того, кто-то может сказать мне, почему конструктор копирования вызывается каждый раз, когда я вернуть * это или объект типа Rectangle любого из моих перегруженных операторов?

Ваши операторы возвращают Rectangle объекты, которые должны быть построены на основе значения, хранящегося в Rectangle*this. Создание Rectangle из Rectangle - это то, что делает конструктор копирования.

Если вы хотите, чтобы вернуть this сам (вместо копии), вы хотите вернуть ссылку на прямоугольнике Rectangle - так Rectangle&

Rectangle & Rectangle::operator+ (const Rectangle &right) 
+0

Почему кто-то проголосовал за мой ответ? – xaxxon

+0

Это «решение», если вы не хотите, чтобы вызывающий экземпляр был вызван. Хотя реализация у вас в operator + лучше подходит для оператора + =, так как она изменяет операнд. – xaxxon

+0

'operator +' не должен возвращать ссылку ... это было правильно, как опубликовано в вопросе, возвращаясь по значению. ('+ =' вернет ссылку на '* this') –

-2

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

Nope - не совсем правильно.

Rectangle Rectangle::operator= (const Rectangle &right) обычно записываются возвращать Rectangle&, так что другие операции могут быть выполнены на назначенном-объект, он может быть передан в качестве аргумента функции и т.д ..

осуществляются неправильно. Распространено первой реализации +=, а затем использовать его в осуществлении +, но если вы хотите написать его самостоятельно это может быть:

Rectangle Rectangle::operator+(Rectangle right) const 
{ 
    right.width += width; 
    right.length += length; 
    return right; 
} 

Таким образом, то right является параметр по значению, поэтому изменения в это не влияет на вызывающего абонента, и вы можете изменить его и вернуть его по значению. Это может показаться неэффективным, но возврат значения по умолчанию обычно оптимизируется (он называется Оптимизацией возвращаемого значения - RVO).

Другой подход, который я упомянул, как выглядит это ...

Rectangle& operator+=(const Rectangle& rhs) 
{ 
    length += rhs.length; 
    width += rhs.width; 
    return *this; 
} 

Rectangle operator+(Rectangle rhs) const 
{ 
    return (rhs += *this); 
} 

Тем не менее, если есть какие-либо неявные конструкторы для вашего типа, необходимо сделать + оператор, не являющийся членом, так что лево- рука на стороне аргумент получает изменение неявно построено:

Rectangle operator+(const Rectangle& lhs, const Rectangle& rhs) 
{ 
    return Rectangle(lhs.length + rhs.length, lhs.width + rhs.width); 
} 

Кроме того, кто-то может сказать мне, почему конструктор копирования вызывается каждый раз, когда я возвращаюсь *this или объективистским t типа Rectangle от любого из моих перегруженных операторов?

В коде в вашем вопросе, возвращаемый тип Rectangle (а не по ссылке), и вы вернетесь *this: что это делает, это сделать копию объекта, на котором функция в испробованы и возвращает эту копию. Конструктор копирования используется для создания копии.

+1

Вы не ответили на его вопрос. – xaxxon

+0

Возможно, стоит упомянуть RVO. – skypjack

+0

@xaxxon: Я обратился к первому вопросу (ну, в буквальном смысле, запрос * «ищет кого-то, кто проверяет» *) в теле сообщения Матимио перед вашим комментарием, и у меня было время, чтобы ответить на второй вопрос (также спросил в названии). Приветствия. –

1

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

Rectangle Rectangle::operator= (const Rectangle &right) 
{ 
    width = right.width; 
    length = right.length; 
    return *this;  <<<<<<<< copy constructor call. 
} 

Вы можете избежать этой копии, если вы вернете этот объект по ссылке.

Rectangle& Rectangle::operator= (const Rectangle &right) 
{ 
    width = right.width; 
    length = right.length; 
    return *this;  <<<<<<<<<<<< No copy constructor call. 
} 
+0

Как это отличается от моего ответа? – xaxxon

+0

@xaxxon Он идет прямо к точке и не показывает плохую подпись для 'operator +'? (Я не проголосовал за вас). – juanchopanza

5

Другие прокомментировали, как возвращение к стоимости вызова ваш конструктор копирования, так что я просто хочу, чтобы ответить на первую часть вопроса:

, если я делаю их правильно, так как хорошо используя * это правильно.

Вашего оператор перегрузка ошибается:

Rectangle Rectangle::operator+ (const Rectangle &right) 
{ 
    width += right.width; 
    length += right.length; 
    return *this; 
} 

это изменяет *this, а затем возвращает его копию. Это не то, что вы ожидаете:

int b = 1, c = 2; 
int a = b + c; 

В приведенных выше пунктах b и c не изменяются. Новое значение создается и сохраняется в a.

Rectangle Rectangle::operator+ (const Rectangle &right) const 
{ 
    Rectangle newValue(*this); // copy ctor temporary 
    newValue.length += right.length; 
    newValue.width += right.width; 
    return newValue; 
} 

или если вы перегружены operator+= вы могли бы написать его с точки зрения, что:

Rectangle Rectangle::operator+ (const Rectangle &right) const 
{ 
    Rectangle newValue(*this); // copy ctor temporary 
    newValue += right; 
    return newValue; 
} 

компилятор обычно будет в состоянии выполнить Return Value Optimization и игнорировать одну из копий, что этот код будет иначе производить.

Во-вторых:

Rectangle Rectangle::operator= (const Rectangle &right) 
{ 
    width = right.width; 
    length = right.length; 
    return *this; 
} 

, как вы узнали, возврат по значению возвращает копию. Оператор = должен возвращать ссылку на текущий объект:

Rectangle& Rectangle::operator= (const Rectangle& right) 
{ 
    width = right.width; 
    length = right.length; 
    return *this; 
} 

Рассмотрим

a = b = c; 

Это выполняет

a.operator=(b.operator=(c)); 

возвращает ссылку сэкономит нам копию продуцирующие параметр в .operator =.

Я закончу с этим предложением для использования * это:

Когда вы возвращаете ссылку, * это говорит «возвращает ссылку на этот конкретный случай моего типа». Когда вы возвращаете значение, и вы говорите «* это», вы говорите «возвращаете экземпляр rvalue (modifiable) этого класса, который выглядит так:», который вызывает копию.

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