(隐式声明)无法引用——它是一个已删除的函数

Cod*_*vil 7 c++ constructor c++11

使用以下代码,我遇到了一个问题。

ABC.h

namespace abcd
{
    class ABC
    {
    public:
        ABC() = delete;
        ABC(const std::string& filename);
        virtual ~ABC();
        ABC(const ABC&) = delete;
        ABC(ABC&&) = default;
    };
}
Run Code Online (Sandbox Code Playgroud)

XYZ.h

using namespace abcd;

class XYZ
{
public:
    void func();
private:
    ABC obj;
    ABC maskfilename(std::string filename);
};
Run Code Online (Sandbox Code Playgroud)

XYZ.cpp

XYZ::func()
{
    obj = maskfilename("abcd.txt"); //Error
}

abcd::ABC XYZ::maskfilename(string filename)
{
    abcd::ABC ret;
    // blah blah...
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

错误:

无法引用“abcd::ABC::operator=(const abcd::ABC &)”(隐式声明)——它是一个已删除的函数

我知道它只是移动构造函数类(ABC)。

使用这个的正确方法是什么?我想保留类maskfilename()中的返回值XYZ,以便可以在类的其他函数中使用它XYZ

我该如何解决这个错误?

jig*_*ius 5

如果您使用 Microsoft 编译器,您将收到 MSVC 错误C2280

编译器检测到引用已删除函数的尝试。此错误可能是由于调用了在源代码中显式标记为 = 已删除的成员函数而引起的 。此错误也可能是由于调用编译器自动声明并标记为已删除的结构或类的隐式特殊成员函数而引起的。有关编译器何时自动生成默认或删除的特殊成员函数的详细信息,请参阅特殊成员函数。

在您的情况下,除了转换构造函数之外,您的类ABC只有一个移动构造函数。由于您声明了移动构造函数,编译器隐式删除了复制赋值运算符。您还显式删除了复制构造函数,即声明了一个复制构造函数,只是删除了一个。这会阻止隐式生成移动赋值运算符。

此行尝试调用您已删除的复制赋值运算符。

obj = maskfilename("abcd.txt"); //Error
Run Code Online (Sandbox Code Playgroud)

你可以在这里阅读更多:

  • 如果显式声明任何构造函数,则不会自动生成默认构造函数。
  • 如果显式声明虚拟析构函数,则不会自动生成默认析构函数。
  • 如果显式声明了移动构造函数或移动赋值运算符,则:
    • 不会自动生成复制构造函数。
    • 不会自动生成复制赋值运算符。
  • 如果显式声明了复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符或析构函数,则:
    • 不会自动生成移动构造函数。
    • 不会自动生成移动赋值运算符。

此外,C++11 标准还指定了以下附加规则:

  • 如果显式声明了复制构造函数或析构函数,则不推荐自动生成复制赋值运算符。
  • 如果显式声明了复制赋值运算符或析构函数,则不推荐自动生成复制构造函数。

由于您希望您的类成为仅移动类,因此只需声明一个移动赋值运算符即可。然后同一行将调用您的移动赋值运算符并将返回的值移动maskfilenameobj

这是您的类的重新设计的实现ABC

class ABC
{
public:
    ABC() = delete;
    ABC(std::string filename) : mFilename(std::move(filename)) {}
    virtual ~ABC() = default;
    ABC(const ABC&) = delete;
    ABC& operator= (const ABC&) = delete;   //deleted copy-assignment operator
    ABC(ABC&&) = default;
    ABC& operator= (ABC&&) = default;   //added move assignment operator
    std::string GetFilename() const { return mFilename; }

private:
    std::string mFilename;
};
Run Code Online (Sandbox Code Playgroud)

在您的类中,XYZ您不能拥有obj类型的成员变量ABC,因为默认构造函数已被删除。如果您需要在其他方法中使用此类对象,则XYZ可以使用唯一的指针来ABC代替。所以我会这样改变:

XYZ.h:

#include "ABC.h"
#include <memory>

class XYZ
{
public:
    void func();

private:
    std::unique_ptr<ABC> obj;
    std::unique_ptr<ABC> maskfilename(std::string filename);
};
Run Code Online (Sandbox Code Playgroud)

XYZ.cpp:

void XYZ::func()
{
    obj = std::move(maskfilename("abcd.txt"));
}

std::unique_ptr<ABC> XYZ::maskfilename(std::string filename)
{
    std::unique_ptr<ABC> ret = std::make_unique<ABC>(filename);
    // blah blah...
    return ret;
}
Run Code Online (Sandbox Code Playgroud)