Сегодня мой вопрос: почему конструктор вызывается в отсутствие предоставленного пользователем оператора присваивания? Я знаю разницу между конструктором и оператором присваивания по отношению к символу =
. Если объект не существовал ранее до этой строки, конструктор неявно вызывается.
std::string name = "Bjarne"; // implicit constructor
Если объект уже существовал ранее до этой строки, вызывается оператор присваивания.
std::string name;
name = "Bjarne"; // assignment operator
Теперь у меня есть class Number
здесь, который является теговым объединением. Это просто число, означающее либо int
, либо float
. У меня есть несколько конструкторов преобразования, которые позволяют пользователю неявно присваивать значения Number
. Я ожидаю, что они будут вызваны в такой ситуации:
Number num1 = 8;
Чтобы точно знать, когда и когда вызывается конструктор, я помещаю операторы print в тела конструкторов.
#include <cstdlib>
#include <iostream>
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
using std::ostream;
/* Unions can be anonymous (unnamed).
* This form is used when nesting a union inside a struct or class that contains an extra data member
* to indicate what the union contains.
* This arrangement is called a tagged union (or managed union).
* It can be used as a "polymorphic" class which can be several things at once, for example to create an array
* of different data types.
*/
class Number {
friend ostream& operator<<(ostream& os, Number& num);
public:
Number(int i = 0) : DATA_TYPE(INTEGER), i(i) { cerr << "Number(" << i << ")\n"; }
Number(unsigned int u) : DATA_TYPE(INTEGER), i(static_cast<int>(u)) { cerr << "Number((signed) " << i << ")\n"; }
Number(float f) : DATA_TYPE(FLOAT), f(f) { cerr << "Number(" << f << ")\n"; }
Number(double d) : DATA_TYPE(FLOAT), f(static_cast<float>(d)) { cerr << "Number((float) " << f << ")\n"; }
Number(const Number& rhs) : DATA_TYPE(rhs.DATA_TYPE), i(rhs.i) { cerr << "Number((Number) " << *this << ")\n"; }
private:
enum data_type { INTEGER, FLOAT } DATA_TYPE;
union {
int i;
float f;
};
};
ostream& operator<<(ostream& os, Number& num)
{
switch (num.DATA_TYPE) {
case Number::INTEGER:
cout << num.i;
break;
case Number::FLOAT:
cout << num.f;
break;
default:
cout << 0;
break;
}
return os;
}
int main()
{
Number num1 = 5; // conversion constructor
cout << num1 << endl;
num1 = 12.5;
cout << num1 << endl;
return EXIT_SUCCESS;
}
Когда я запускаю этот код, он выдает неожиданный вывод для меня:
Number(5)
5
Number((float) 12.5)
12.5
Я вижу, что при инициализации Number num1
вызывается конструктор, принимающий int
в качестве параметра. Затем я печатаю значение num1
. Затем на следующей строке кажется, что вызывается конструктор, принимающий double
в качестве параметра. Это странно. До этой строки num1
уже существовал как объект. Так что вместо этого он должен логически вызывать оператор присваивания. Вместо этого я не определил оператор присваивания, поэтому я предполагаю, что будет вызван оператор присваивания, сгенерированный компилятором.
Я хочу знать, что произойдет, если я не предоставлю пользователю оператор присваивания? num1 = something;
Вызывается ли оператор присваивания по умолчанию, предоставляемый компилятором, или конструктор? Что происходит, когда конструктор вызывается для объекта, который уже существует? Этот объект "реконструирован"? Так что же на самом деле происходит в этом случае?