C++ 为什么没有用户的类提供cp/mv-ctor,并且具有虚拟函数,但没有虚拟基,而没有“繁琐的cp/mv-ctor”?

C++ 为什么没有用户的类提供cp/mv-ctor,并且具有虚拟函数,但没有虚拟基,而没有“繁琐的cp/mv-ctor”?,c++,c++11,language-lawyer,C++,C++11,Language Lawyer,根据标准: 如果类X的复制/移动构造函数不是用户提供的,并且 -类X没有虚拟函数10.3和虚拟基类10.1,以及 -选择用于复制/移动每个直接基类子对象的构造函数非常简单,并且 -对于类类型或其数组的X的每个非静态数据成员,构造函数 选择复制/移动该成员是微不足道的 否则,复制/移动构造函数是非常重要的 我认为标准引入了trival cp/mv ctor的概念,以推断您可以使用std::memcpy而不是调用构造函数来复制类,并且不会有未定义的行为 然而,该标准不允许虚拟函数的存在,我认为这与繁

根据标准:

如果类X的复制/移动构造函数不是用户提供的,并且

-类X没有虚拟函数10.3和虚拟基类10.1,以及

-选择用于复制/移动每个直接基类子对象的构造函数非常简单,并且

-对于类类型或其数组的X的每个非静态数据成员,构造函数 选择复制/移动该成员是微不足道的

否则,复制/移动构造函数是非常重要的

我认为标准引入了trival cp/mv ctor的概念,以推断您可以使用std::memcpy而不是调用构造函数来复制类,并且不会有未定义的行为

然而,该标准不允许虚拟函数的存在,我认为这与繁琐的cp/mv的精神背道而驰。带有指向虚拟函数的vtable的类仍然可以使用std::memcpy进行复制,并且具有正确的行为。毕竟,您不能在运行时更改一个类的vtable,这将破坏该类的其他实例


那么,为什么没有用户的类不能提供cp/mv-ctor并具有虚拟函数,但没有虚拟基的类却具有繁琐的cp/mv-ctor呢?

这不是一种简单的类型,因为确保vptr指向正确的vtable并不像复制指针的值那样简单。我们可以只复制基本子对象。我们不需要总是处理最派生的对象类型

void bar(base const& b) { 
  b.overriden_function();
}

void foo(base const& b) {
  auto other_b = b;
  bar(other_b);
}

int main() {
  derived d;
  foo(d);
}
让我们假设基数很小。照你说的做。b的vptr指向派生的vtable。现在我们得到了一个对象,它的vtpr指向错误的vtable。我们调用一个重写函数


考虑一个简单的例子:

#include <iostream>

struct ConcreteBase {
    virtual void method() {
        std::cout << "Basic implementation" << std::endl;
    }
};
struct Derived: ConcreteBase {
    Derived(int x): extraState{x} {}
    void method() {
        std::cout << "Overridden (" << extraState << ')' << std::endl;
    }
private:
    const int extraState;
};

int main() {
    ConcreteBase const &b = Derived(42);
    ConcreteBase b1{b};
    b1.method();
}

您将如何使用memcpy在此处复制vtable?更广泛地说,您将如何使ConcreteBase的复制子对象平凡化?

当您仅从派生对象复制基本子对象时会发生什么?我指的是memcpy,但cp/mv-ctor指的是从同一类型复制或移动数据。TIVAL的整个概念是建立在同一个类的基础上的,派生类或基类与此无关,考虑结构B {VirtualB{}};结构D:B{};dx;B y,*p;p=&x;memcpy&y,p,sizeof y@您可以有一个指向派生类的基类指针。在这种情况下,您将复制错误的vtable指针。