可初始化但不可赋值的对象

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; 工作正常。

您可以显式声明取 intdeleted (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 以禁止从 intObject 的隐式转换,然后使 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&);
};