Не могли бы вы объяснить мне вывод следующего кода? Переменная меняет свое значение в конце присваивания.
#include <iostream>
#include <new>
using namespace std;
template<class CRTP>
class object_t {
public:
object_t<CRTP> &operator=(const object_t<CRTP> &a) {
((CRTP*)this)->~CRTP();
new ((CRTP*)this) CRTP(*(const CRTP*)&a);
cout << "Value in assignment: " << ((CRTP*)this)->n << endl;
return *this;
}
};
class darr_t : public object_t<darr_t> {
public:
int n;
darr_t(const darr_t &a) : n(a.n + 1) {
cout << "Value in constructor: " << n << endl;
}
darr_t(int pn) : n(pn) {}
};
int main() {
darr_t tmp(42);
darr_t tmp2(55);
tmp = tmp2;
cout << "Value in main: " << tmp.n << endl;
return 0;
}
Выход:
Значение в конструкторе: 56
Значение в назначении: 56
Значение в основном: 55
Ожидаемый результат:
Значение в конструкторе: 56
Значение в назначении: 56
Значение в основном: 56
Редактировать:
Спасибо @ Cheersandhth.-Alf и @ Mr_Hic-up ответы!
Проблема в том, что по умолчанию darr_t :: operator = сначала вызывает назначение базового типа, но после этого вызывает назначение (переопределение) для членов объекта darr_t!
Вы наблюдаете за поведением, потому что:
darr_t
,Вот соответствующая документация от http://en.cppreference.com/w/cpp/language/as_operator:
Неявно объявленный оператор присваивания копии
Если для типа класса не заданы пользовательские операторы назначения копирования (
struct
,class
, или жеunion
), компилятор всегда объявляет его как встроенный открытый член класса. Этот неявно объявленный оператор присваивания копии имеет видT& T::operator=(const T&)
если все следующее верно:каждая прямая база
B
изT
имеет оператор присваивания копии, параметры которогоB
или жеconst B&
или жеconst volatile B&
каждый элемент не статических данных
M
изT
типа класса или массива типа класса имеет оператор присваивания копии, параметры которогоM
или жеconst M&
или жеconst volatile M&
В противном случае неявно объявленный оператор присваивания копии объявляется как
T& T::operator=(T&)
, (Обратите внимание, что из-за этих правил неявно объявленный оператор присваивания копии не может связываться с переменным аргументом lvalue)
new ((CRTP*)this) CRTP(*(const CRTP*)&a);
Та магия указателя, которую вы пытаетесь использовать, не делает того, чего вы ожидаете. Добавляем несколько строк, чтобы распечатать адреса объекта перед печатью переменной yields (на моем компьютере):
Address in constructor: 0x7fff56264610
Value in constructor: 56
Address in assignment: 0x7fff56264610
Value in assignment: 56
Address in main: 0x7fff56264618
Value in main: 55