可初始化但不可赋值的对象
Objects that can be initialized but not assigned
我需要创建一个class其对象可以初始化但不能赋值。
我想也许我可以通过不定义赋值运算符来做到这一点,但编译器使用构造函数来进行赋值。
我需要这样:
Object a=1; // OK
a=1; // Error
我该怎么做?
您可以delete赋值运算符:
#include <iostream>
using namespace std;
struct Object
{
Object(int) {}
Object& operator=(int) = delete;
};
int main()
{
Object a=1; // OK
a=1; // Error
}
备选方案
您可以使用 explicit 关键字:
#include <iostream>
using namespace std;
struct Object
{
explicit Object(int) {}
};
int main()
{
Object a(1); // OK - Uses explicit constructor
a=1; // Error
}
更新
正如 user2079303 在评论中提到的:
It might be worth mentioning that the alternative solution does not prevent regular copy/move assignment like a=Object(1)
这可以通过使用来避免:Object& operator=(const Object&) = delete;
I hoped this would be so by not defining the assignment operator
这不起作用,因为复制赋值运算符(以 const Object&
作为参数)是隐式生成的。当你写 a = 1
时,生成的复制赋值运算符将被尝试调用,并且 1
可以通过转换构造函数 Object::Object(int)
隐式转换为 Object
;然后 a = 1;
工作正常。
您可以显式声明取 int
为 deleted (C++11 起)的赋值运算符;在重载决策中,它将在复制赋值运算符之前被选择。
If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected.
例如
struct Object {
Object(int) {}
Object& operator=(int) = delete;
};
还有其他一些有副作用的解决方案。您可以将 Object::Object(int)
声明为 explicit
以禁止从 int
到 Object
的隐式转换,然后使 a = 1
失败。但请注意,这也会使 Object a = 1;
失败,因为复制初始化不考虑 explicit
构造函数。或者您也可以将复制赋值运算符标记为已删除,但这会使 Object
之间的赋值也失败。
How can I do it?
选项 1:
构造函数explicit
struct Object
{
explicit Object(int in) {}
};
选项 2:
delete
赋值运算符。
struct Object
{
Object(int in) {}
Object& operator=(int in) = delete;
};
您可以使用以上两个选项。
struct Object
{
explicit Object(int in) {}
Object& operator=(int in) = delete;
};
选项 3:
如果初始化后不想赋值,可以delete
参数类型为Object
的赋值运算符。
struct Object
{
explicit Object(int in) {}
Object& operator=(Object const& in) = delete;
};
这将阻止使用:
Object a(1);
a = Object(2); // Error
a = 2; // Error
制作 a
const 就可以了
const Object a=1; // OK
现在您将无法为 a
分配任何值,因为 a
被声明为 const
。注意,如果把a
声明为const
,声明的时候需要初始化a
。
一旦您将 a
声明为 const
并对其进行了初始化,您将无法将任何其他值分配给 a
a=1; //error
删除的函数仅适用于 C++11 及更高版本,对于较旧的编译器,您可以使赋值运算符 private
.
struct Object
{
Object(int) {}
private:
Object& operator=(int);
};
编译器现在将为
抛出错误
Object a=1; //ok
a=2; // error
但你仍然可以做到
Object a=1,b=2;
b=a;
因为默认赋值运算符不会被编译器生成。所以标记默认分配 private
将解决这个问题。
struct Object
{
Object(int) {}
private:
Object& operator=(Object&);
};
我需要创建一个class其对象可以初始化但不能赋值。
我想也许我可以通过不定义赋值运算符来做到这一点,但编译器使用构造函数来进行赋值。
我需要这样:
Object a=1; // OK
a=1; // Error
我该怎么做?
您可以delete赋值运算符:
#include <iostream>
using namespace std;
struct Object
{
Object(int) {}
Object& operator=(int) = delete;
};
int main()
{
Object a=1; // OK
a=1; // Error
}
备选方案
您可以使用 explicit 关键字:
#include <iostream>
using namespace std;
struct Object
{
explicit Object(int) {}
};
int main()
{
Object a(1); // OK - Uses explicit constructor
a=1; // Error
}
更新
正如 user2079303 在评论中提到的:
It might be worth mentioning that the alternative solution does not prevent regular copy/move assignment like
a=Object(1)
这可以通过使用来避免:Object& operator=(const Object&) = delete;
I hoped this would be so by not defining the assignment operator
这不起作用,因为复制赋值运算符(以 const Object&
作为参数)是隐式生成的。当你写 a = 1
时,生成的复制赋值运算符将被尝试调用,并且 1
可以通过转换构造函数 Object::Object(int)
隐式转换为 Object
;然后 a = 1;
工作正常。
您可以显式声明取 int
为 deleted (C++11 起)的赋值运算符;在重载决策中,它将在复制赋值运算符之前被选择。
If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected.
例如
struct Object {
Object(int) {}
Object& operator=(int) = delete;
};
还有其他一些有副作用的解决方案。您可以将 Object::Object(int)
声明为 explicit
以禁止从 int
到 Object
的隐式转换,然后使 a = 1
失败。但请注意,这也会使 Object a = 1;
失败,因为复制初始化不考虑 explicit
构造函数。或者您也可以将复制赋值运算符标记为已删除,但这会使 Object
之间的赋值也失败。
How can I do it?
选项 1:
构造函数explicit
struct Object
{
explicit Object(int in) {}
};
选项 2:
delete
赋值运算符。
struct Object
{
Object(int in) {}
Object& operator=(int in) = delete;
};
您可以使用以上两个选项。
struct Object
{
explicit Object(int in) {}
Object& operator=(int in) = delete;
};
选项 3:
如果初始化后不想赋值,可以delete
参数类型为Object
的赋值运算符。
struct Object
{
explicit Object(int in) {}
Object& operator=(Object const& in) = delete;
};
这将阻止使用:
Object a(1);
a = Object(2); // Error
a = 2; // Error
制作 a
const 就可以了
const Object a=1; // OK
现在您将无法为 a
分配任何值,因为 a
被声明为 const
。注意,如果把a
声明为const
,声明的时候需要初始化a
。
一旦您将 a
声明为 const
并对其进行了初始化,您将无法将任何其他值分配给 a
a=1; //error
删除的函数仅适用于 C++11 及更高版本,对于较旧的编译器,您可以使赋值运算符 private
.
struct Object
{
Object(int) {}
private:
Object& operator=(int);
};
编译器现在将为
抛出错误Object a=1; //ok
a=2; // error
但你仍然可以做到
Object a=1,b=2;
b=a;
因为默认赋值运算符不会被编译器生成。所以标记默认分配 private
将解决这个问题。
struct Object
{
Object(int) {}
private:
Object& operator=(Object&);
};