如何将移动构造函数与已删除的默认构造函数一起使用
How to use move constructor with deleted default consturctor
我有这样一段代码:
struct Base {
Base() = default;
};
struct Derive: public Base
{
Derive() = default;
Derive(const Derive&) = delete;
Derive(Derive&& p) { *this = std::move(p); }
Derive& operator = (const Derive& p) = delete;
Derive& operator = (Derive&& p) {
return *this;
}
};
int main() {
Derive p;
}
编译成功。现在我想稍微更改 class 定义,以便 Base 或 Derived class 始终使用特定整数参数构造,并且在没有此类参数的情况下永远不会构造。
因此,如果我尝试以下更改:
struct Base {
Base() = delete;
Base(int a_) : a{a_} {};
private:
int a; //new mandatory param;
};
struct Derive: public Base
{
Derive() = delete;
Derive(int a_) : Base(a_) {};
Derive(const Derive&) = delete;
Derive(Derive&& p) { *this = std::move(p); }
Derive& operator = (const Derive& p) = delete;
Derive& operator = (Derive&& p) {
return *this;
}
};
int main() {
Derive p{1};
}
我收到编译错误
main.cpp:15:2: error: call to deleted constructor of 'Base'
Derive(Derive&& p) { *this = std::move(p); }
^
main.cpp:4:2: note: 'Base' has been explicitly marked deleted here
Base() = delete;
^
1 error generated.
显然这种方式行不通。那么我该如何修改代码使其编译并且没有参数构造函数永远不会被调用而不会出错?
的问题
Derive(Derive&& p) xxx { *this = std::move(p); }
是在 xxx
部分你有一个空的 member initialization list。这意味着编译器将为基 class 插入一个,因为在执行构造函数主体之前,所有成员都在成员初始化列表中进行了初始化。该编译器生成的版本看起来像
Derive(Derive&& p) : Base() { *this = std::move(p); }
而且您无法执行 Base()
,因为它已被删除。你要的是
Derive(Derive&& p) : Base(std::move(p)) {}
甚至更短
Derive(Derive&& p) = default;
您不需要显式删除库中的默认构造函数 class。简单地定义一个需要参数的 ctor 会阻止编译器生成默认的 ctor,所以你的基础 class 可以只是:
struct Base {
Base(int a_) : a{a_} {};
private:
int a; //new mandatory param;
};
同样,在派生的 class 中,定义一个接受参数的构造函数也会阻止编译器为其生成默认构造函数。至少到目前为止,您提到的任何内容似乎都表明您需要为派生 class 显式定义任何特殊成员函数,因此它可以变得简单:
struct Derive: public Base
{
Derive(int a_) : Base(a_) {};
};
...现在代码编译得很好,任何尝试创建 Base
或 Derive
的实例而不指定 ctor 的参数都会失败(不会编译).
顺便说一句,因为您将它用作基础 class,您 可能 希望 Base
使其 dtor 虚拟化。在这里定义为默认可能比较合适。
我有这样一段代码:
struct Base {
Base() = default;
};
struct Derive: public Base
{
Derive() = default;
Derive(const Derive&) = delete;
Derive(Derive&& p) { *this = std::move(p); }
Derive& operator = (const Derive& p) = delete;
Derive& operator = (Derive&& p) {
return *this;
}
};
int main() {
Derive p;
}
编译成功。现在我想稍微更改 class 定义,以便 Base 或 Derived class 始终使用特定整数参数构造,并且在没有此类参数的情况下永远不会构造。
因此,如果我尝试以下更改:
struct Base {
Base() = delete;
Base(int a_) : a{a_} {};
private:
int a; //new mandatory param;
};
struct Derive: public Base
{
Derive() = delete;
Derive(int a_) : Base(a_) {};
Derive(const Derive&) = delete;
Derive(Derive&& p) { *this = std::move(p); }
Derive& operator = (const Derive& p) = delete;
Derive& operator = (Derive&& p) {
return *this;
}
};
int main() {
Derive p{1};
}
我收到编译错误
main.cpp:15:2: error: call to deleted constructor of 'Base'
Derive(Derive&& p) { *this = std::move(p); }
^
main.cpp:4:2: note: 'Base' has been explicitly marked deleted here
Base() = delete;
^
1 error generated.
显然这种方式行不通。那么我该如何修改代码使其编译并且没有参数构造函数永远不会被调用而不会出错?
Derive(Derive&& p) xxx { *this = std::move(p); }
是在 xxx
部分你有一个空的 member initialization list。这意味着编译器将为基 class 插入一个,因为在执行构造函数主体之前,所有成员都在成员初始化列表中进行了初始化。该编译器生成的版本看起来像
Derive(Derive&& p) : Base() { *this = std::move(p); }
而且您无法执行 Base()
,因为它已被删除。你要的是
Derive(Derive&& p) : Base(std::move(p)) {}
甚至更短
Derive(Derive&& p) = default;
您不需要显式删除库中的默认构造函数 class。简单地定义一个需要参数的 ctor 会阻止编译器生成默认的 ctor,所以你的基础 class 可以只是:
struct Base {
Base(int a_) : a{a_} {};
private:
int a; //new mandatory param;
};
同样,在派生的 class 中,定义一个接受参数的构造函数也会阻止编译器为其生成默认构造函数。至少到目前为止,您提到的任何内容似乎都表明您需要为派生 class 显式定义任何特殊成员函数,因此它可以变得简单:
struct Derive: public Base
{
Derive(int a_) : Base(a_) {};
};
...现在代码编译得很好,任何尝试创建 Base
或 Derive
的实例而不指定 ctor 的参数都会失败(不会编译).
顺便说一句,因为您将它用作基础 class,您 可能 希望 Base
使其 dtor 虚拟化。在这里定义为默认可能比较合适。