为什么从原始类型到 class 类型的转换会破坏对象值?
Why primitive to class type conversion destroys object values?
为什么在下面的代码中,当我设置 c1 = 10
时,会破坏对象的变量 (a
、b
、c
) 的所有其他值。该语句应调用构造函数,并且在定义构造函数时将 a
的值设置为 10
,但是当我尝试访问 b
和 c
的值时;它给了我垃圾值。
#include<iostream>
using namespace std;
class abc{
private:
// properties
int a,b, c;
public:
void setdata(int x,int y)
{
a = x;
b = y;
}
void showdata(){
cout << "a = " << a << " b = " << b << "\n";
}
// constructors
abc(){}
abc(int k)
{
a=k;
}
};
int main()
{
abc c1; // object intialization
c1.setdata(6,7); // setting values of properties
c1.showdata(); // printing values
c1 = 10; // primitive to class type conversion, constructor is being called
c1.showdata(); // why value of b and other variables is getting changed ?
return 0;
}
这相当于
c1 = abc(10);
构造函数abc(int k)
没有初始化值b
和c
,因此成员变量包含一些随机值。这些来自临时 abc(10)
对象的随机值随后被复制到 c1
.
构造函数也是如此abc()
,这里两个成员变量都没有初始化,所以都是“垃圾”值。当你在构建
后立即调用 showdata
时,你会看到这一点
abc c1;
c1.showdata();
当你写道:
c1 = 10;
在右侧,转换构造函数用于创建临时类型abc
对象。
Next,赋值运算符用于将右侧的临时对象赋值给左侧的对象.
此外,请注意转换构造函数 abc(int k);
仅将 分配给数据成员 a
并保留数据成员 b
和 c
原样。但是由于您没有显式初始化成员 b
和 c
,它们具有 不确定值 。 using/accessing 这些值(b
和 c
)导致 未定义的行为。
这就是为什么建议
always initialize built in types in local/block scope.
要解决这个你可以使用in-class初始化器如下所示:
class abc{
private:
// USE IN-CLASS INITIALIZERS
int a = 0,b = 0, c =0;
public:
void setdata(int x,int y)
{
a = x;
b = y;
}
void showdata(){
cout << "a = " << a << " b = " << b << "\n";
}
// constructors
abc(){}
abc(int k)
{
a=k;
}
};
也不是在构造函数体内给数据成员a
赋值,而是应该使用构造函数初始化列表来初始化它,如下所示:
class abc{
private:
// USE IN-CLASS INITIALIZERS
int a = 0,b = 0, c =0;
public:
void setdata(int x,int y)
{
a = x;
b = y;
}
void showdata(){
cout << "a = " << a << " b = " << b << "\n";
}
// constructors
abc(){}
//use constructor initializer list
abc(int k): a{k}
{
//no need to assign to `a` here
}
};
你的线路
c1 = 10;
创建一个新对象,其中只调用您的构造函数 abc(int k)
。现在你有了一个临时对象,它将被移动到现有的对象中 c1
。由于您只覆盖变量 a
,所有其他变量都没有明确设置。
我不知道这是否是有意为之的行为,即您创建了一个临时对象,该对象将被移动到现有对象中。如果你不想要它,你应该让你的构造函数 explicit
.
顺便说一句:您的构造函数没有初始化您的变量 a
而是覆盖了它。对于 int
类型,这无关紧要,但对于其他不可默认构造的类型,它将不起作用。
您应该始终使用构造函数初始化程序来初始化您的变量,例如:
abc(int k): a{k}{}
事实上 c1 = 10;
调用了 2 个不同的步骤:
- 临时
abc
对象是从 abc(int k)
构造函数构造的 - 显然它的 b 和 c 值未设置
- 然后使用将替换所有成员的移动赋值运算符之一将临时分配给
c1
。
之后,临时文件被销毁。
如果您有充分的理由不覆盖副本中的先前值,您可以提供自定义复制或移动赋值运算符。但请注意,每次作业都会用到它。
为什么在下面的代码中,当我设置 c1 = 10
时,会破坏对象的变量 (a
、b
、c
) 的所有其他值。该语句应调用构造函数,并且在定义构造函数时将 a
的值设置为 10
,但是当我尝试访问 b
和 c
的值时;它给了我垃圾值。
#include<iostream>
using namespace std;
class abc{
private:
// properties
int a,b, c;
public:
void setdata(int x,int y)
{
a = x;
b = y;
}
void showdata(){
cout << "a = " << a << " b = " << b << "\n";
}
// constructors
abc(){}
abc(int k)
{
a=k;
}
};
int main()
{
abc c1; // object intialization
c1.setdata(6,7); // setting values of properties
c1.showdata(); // printing values
c1 = 10; // primitive to class type conversion, constructor is being called
c1.showdata(); // why value of b and other variables is getting changed ?
return 0;
}
这相当于
c1 = abc(10);
构造函数abc(int k)
没有初始化值b
和c
,因此成员变量包含一些随机值。这些来自临时 abc(10)
对象的随机值随后被复制到 c1
.
构造函数也是如此abc()
,这里两个成员变量都没有初始化,所以都是“垃圾”值。当你在构建
showdata
时,你会看到这一点
abc c1;
c1.showdata();
当你写道:
c1 = 10;
在右侧,转换构造函数用于创建临时类型abc
对象。
Next,赋值运算符用于将右侧的临时对象赋值给左侧的对象.
此外,请注意转换构造函数 abc(int k);
仅将 分配给数据成员 a
并保留数据成员 b
和 c
原样。但是由于您没有显式初始化成员 b
和 c
,它们具有 不确定值 。 using/accessing 这些值(b
和 c
)导致 未定义的行为。
这就是为什么建议
always initialize built in types in local/block scope.
要解决这个你可以使用in-class初始化器如下所示:
class abc{
private:
// USE IN-CLASS INITIALIZERS
int a = 0,b = 0, c =0;
public:
void setdata(int x,int y)
{
a = x;
b = y;
}
void showdata(){
cout << "a = " << a << " b = " << b << "\n";
}
// constructors
abc(){}
abc(int k)
{
a=k;
}
};
也不是在构造函数体内给数据成员a
赋值,而是应该使用构造函数初始化列表来初始化它,如下所示:
class abc{
private:
// USE IN-CLASS INITIALIZERS
int a = 0,b = 0, c =0;
public:
void setdata(int x,int y)
{
a = x;
b = y;
}
void showdata(){
cout << "a = " << a << " b = " << b << "\n";
}
// constructors
abc(){}
//use constructor initializer list
abc(int k): a{k}
{
//no need to assign to `a` here
}
};
你的线路
c1 = 10;
创建一个新对象,其中只调用您的构造函数 abc(int k)
。现在你有了一个临时对象,它将被移动到现有的对象中 c1
。由于您只覆盖变量 a
,所有其他变量都没有明确设置。
我不知道这是否是有意为之的行为,即您创建了一个临时对象,该对象将被移动到现有对象中。如果你不想要它,你应该让你的构造函数 explicit
.
顺便说一句:您的构造函数没有初始化您的变量 a
而是覆盖了它。对于 int
类型,这无关紧要,但对于其他不可默认构造的类型,它将不起作用。
您应该始终使用构造函数初始化程序来初始化您的变量,例如:
abc(int k): a{k}{}
事实上 c1 = 10;
调用了 2 个不同的步骤:
- 临时
abc
对象是从abc(int k)
构造函数构造的 - 显然它的 b 和 c 值未设置 - 然后使用将替换所有成员的移动赋值运算符之一将临时分配给
c1
。
之后,临时文件被销毁。
如果您有充分的理由不覆盖副本中的先前值,您可以提供自定义复制或移动赋值运算符。但请注意,每次作业都会用到它。