抽象类和移动语义
Abstract classes and move semantics
根据“五规则”,当我声明以下之一时:复制或移动操作或析构函数我必须编写所有它们,因为编译器不会为我生成它们(其中一些)。但是,如果我的 class (A
) 派生自具有虚拟析构函数的抽象 class,这是否意味着 class A
中的析构函数将被视为 "user-defined"?因此,移动语义是否不适用于此 class A
的对象,因为编译器不会为我生成移动构造函数?
struct Interface {
virtual void myFunction() = 0;
virtual ~Interface() {};
};
struct A : public Interface {
void myFunction() override {};
};
在[class.copy]中:
If the definition of a class X
does not explicitly declare a move constructor, one will be implicitly declared
as defaulted if and only if
(9.1) — X does not have a user-declared copy constructor,
(9.2) — X does not have a user-declared copy assignment operator,
(9.3) — X does not have a user-declared move assignment operator, and
(9.4) — X does not have a user-declared destructor.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise
would have invoked the move constructor may instead invoke a copy constructor. —end note ]
Interface
确实有一个用户声明的析构函数,因此 Interface
的移动构造函数不会被隐式声明为默认。但是 A
不符合这些要点中的任何一个 - 所以它 将 有一个默认的隐式移动构造函数。根据注释,A(A&& )
将只复制 Interface
部分。我们可以通过将成员添加到 Interface
和 A
:
来验证这一点
#include <iostream>
template <char c>
struct Obj {
Obj() { std::cout << "default ctor" << c << "\n"; }
Obj(const Obj&) { std::cout << "copy ctor" << c << "\n"; }
Obj(Obj&&) { std::cout << "move ctor" << c << "\n"; }
};
struct Interface {
virtual void myFunction() = 0;
virtual ~Interface() {};
Obj<'I'> base;
};
struct A : public Interface {
void myFunction() override {};
Obj<'A'> derived;
};
int main() {
A a1; // default I, default A
std::cout << "---\n";
A a2(std::move(a1)); // copy I, move A
std::cout << "---\n";
A a3(a2); // copy I, copy A
}
根据“五规则”,当我声明以下之一时:复制或移动操作或析构函数我必须编写所有它们,因为编译器不会为我生成它们(其中一些)。但是,如果我的 class (A
) 派生自具有虚拟析构函数的抽象 class,这是否意味着 class A
中的析构函数将被视为 "user-defined"?因此,移动语义是否不适用于此 class A
的对象,因为编译器不会为我生成移动构造函数?
struct Interface {
virtual void myFunction() = 0;
virtual ~Interface() {};
};
struct A : public Interface {
void myFunction() override {};
};
在[class.copy]中:
If the definition of a class
X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
(9.1) — X does not have a user-declared copy constructor,
(9.2) — X does not have a user-declared copy assignment operator,
(9.3) — X does not have a user-declared move assignment operator, and
(9.4) — X does not have a user-declared destructor.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note ]
Interface
确实有一个用户声明的析构函数,因此 Interface
的移动构造函数不会被隐式声明为默认。但是 A
不符合这些要点中的任何一个 - 所以它 将 有一个默认的隐式移动构造函数。根据注释,A(A&& )
将只复制 Interface
部分。我们可以通过将成员添加到 Interface
和 A
:
#include <iostream>
template <char c>
struct Obj {
Obj() { std::cout << "default ctor" << c << "\n"; }
Obj(const Obj&) { std::cout << "copy ctor" << c << "\n"; }
Obj(Obj&&) { std::cout << "move ctor" << c << "\n"; }
};
struct Interface {
virtual void myFunction() = 0;
virtual ~Interface() {};
Obj<'I'> base;
};
struct A : public Interface {
void myFunction() override {};
Obj<'A'> derived;
};
int main() {
A a1; // default I, default A
std::cout << "---\n";
A a2(std::move(a1)); // copy I, move A
std::cout << "---\n";
A a3(a2); // copy I, copy A
}