c++ - move 构造函数不是继承的,也不是默认生成的

标签 c++ c++11 inheritance c++17 move-semantics

我尝试扩展 std::ifstream使用一个函数可以更轻松地读取二进制变量,令我惊讶的是,使用 using std::ifstream::ifstream; move 构造函数不是继承的。更糟糕的是,它被明确删除。

#include <fstream>

class BinFile: public std::ifstream
{
public:
    using std::ifstream::ifstream;
    //BinFile(BinFile&&) = default; // <- compilation warning: Explicitly defaulted move constructor is implicitly deleted

    template<typename T>
    bool read_binary(T* var, std::streamsize nmemb = 1)
    {
        const std::streamsize count = nmemb * sizeof *var;
        read(reinterpret_cast<char*>(var), count);
        return gcount() == count;
    }
};

auto f()
{
    std::ifstream ret("some file"); // Works!
    //BinFile ret("some file"); // <- compilation error: Call to implicitly-deleted copy constructor of 'BinFile'
    return ret;
}

我不想显式实现 move 构造函数,因为它只是感觉不对。问题:
  • 为什么会被删除?
  • 删除它有意义吗?
  • 有没有办法修复我的类,以便正确继承 move 构造函数?
  • 最佳答案

    问题是basic_istream ( basic_ifstream 的基础,其中模板 ifstream 是实例化)实际上继承自 basic_ios , 和 basic_ios有一个删除的 move 构造函数(除了 protected 默认构造函数)。

    (虚拟继承的原因是 fstream 的继承树中有一个菱形,继承自 ifstreamofstream 。)

    一个鲜为人知和/或容易忘记的事实是,最派生的类构造函数直接调用其(继承的)虚基构造函数,如果它没有在基或成员初始化列表中明确这样做,则虚拟基的默认值构造函数将被调用。然而(这更加模糊),对于隐式定义或声明为默认的复制/move 构造函数,选择的虚拟基类构造函数不是默认构造函数,而是对应的复制/move 构造函数;如果它被删除或不可访问,则最派生的类复制/move 构造函数将被定义为已删除。

    这是一个示例(可以追溯到 C++98):

    struct B { B(); B(int); private: B(B const&); };
    struct C : virtual B { C(C const&) : B(42) {} };
    struct D : C {
        // D(D const& d) : C(d) {}
    };
    D f(D const& d) { return d; } // fails
    

    (这里 B 对应于 basic_iosC 对应于 ifstreamD 对应于您的 BinFilebasic_istream 对于演示来说是不必要的。)

    如果 D 的手动复制构造函数没有注释,程序会编译但会调用 B::B() ,不是 B::B(int) .这就是为什么从没有明确授予您这样做的权限的类继承是一个坏主意的原因之一;如果该构造函数被称为最派生类构造函数,则您可能不会调用由您继承的类的构造函数调用的相同虚拟基构造函数。

    至于你能做什么,我相信手写的 move 构造函数应该可以工作,因为在 libstdc++ 和 libcxx 中 basic_ifstream 的 move 构造函数|不调用 basic_ios 的非默认构造函数(有一个,来自 basic_streambuf 指针),而是在构造函数体中初始化它(看起来这就是 [ifstream.cons]/4 所说的)。值得一读Extending the C++ Standard Library by inheritance?对于其他潜在的问题。

    关于c++ - move 构造函数不是继承的,也不是默认生成的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61563961/

    相关文章:

    c++ - 模板函数在编译期间被报告为 "undefined reference"

    c++ - 两个 unordered_maps 的交集

    c++ - 使用boost图形库: how to create a graph by reading edge lists from file

    c++ - C++ 宏中的模板?

    c++ - 从其他函数访问变量 C++

    c++ - 函数模板不起作用,出现错误 "No suitable user-defined conversion"

    c++ - C++11 标准是否提供类似 boost::any 的东西?

    Ruby、类和继承

    java - Java 中的动态转换

    kotlin - 您如何在Kotlin中进行合格的父类(super class)构造函数调用?