【问题标题】:Abstract classes and move semantics抽象类和移动语义
【发布时间】:2015-07-02 06:40:05
【问题描述】:

根据“五法则”,当我声明以下之一时:复制或移动操作或析构函数我必须编写所有这些,因为编译器不会为我生成它们(其中一些)。但是,如果我的类 (A) 派生自具有虚拟析构函数的抽象类,这是否意味着 A 类中的析构函数将被视为“用户定义的”?因此,移动语义是否不适用于此类A 的对象,因为编译器不会为我生成移动构造函数?

struct Interface {
    virtual void myFunction() = 0;
    virtual ~Interface() {};
};

struct A : public Interface {
    void myFunction() override {};
};

【问题讨论】:

  • 抽象类不能被实例化。
  • 你用的是什么编译器?
  • @MikeMB 我没有使用任何特定的编译器。
  • 如果你需要一个虚拟析构函数,但又不想抑制任何东西,你可以使用virtual ~T() = default;

标签: c++ c++11 move-semantics


【解决方案1】:

在 [class.copy] 中:

如果类X的定义没有显式声明移动构造函数,则会隐式声明 当且仅当
(9.1) — X 没有用户声明的复制构造函数,
(9.2) — X 没有用户声明的复制赋值运算符,
(9.3) — X 没有用户声明的移动赋值运算符,并且
(9.4) — X 没有用户声明的析构函数。
[ 注意: 当移动构造函数没有被隐式声明或显式提供时,否则表达式 将调用移动构造函数可能会调用复制构造函数。 ——尾注]

Interface 确实有一个用户声明的析构函数,所以Interface 的移动构造函数不会被隐式声明为默认值。但是A 不符合这些要点中的任何一个 - 所以它有一个默认的隐式移动构造函数。 A(A&& ) 将根据注释复制 Interface 部分。我们可以通过将成员添加到InterfaceA 来验证这一点:

#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
}

【讨论】:

  • Interface 获取默认的复制构造函数是自 C++11 以来已弃用的功能。不过,它仍然存在于最近的草稿中。
  • @dyp "如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。"在未来的哪个版本中,这将被删除?可能是 C++17?
  • 我不知道。 N3839 探索这个,不知道发生了什么。 -- 编辑:EWG #55 happened 我希望我们很快就会收到更多关于它的警告(例如 clang++ -Wdeprecated)。
猜你喜欢
  • 2017-01-19
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
  • 2016-02-04
相关资源
最近更新 更多