Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一个非平凡的复制构造函数做什么? 在C++中,如果没有定义复制构造函数,编译器会为您这样做。若定义了一个,编译器将不会。编译器生成的复制构造函数可以是普通的,也可以是非普通的。在一个普通的复制构造函数中,它执行一个成员级的复制。就这样_C++_Copy Constructor_Virtual Functions - Fatal编程技术网

一个非平凡的复制构造函数做什么? 在C++中,如果没有定义复制构造函数,编译器会为您这样做。若定义了一个,编译器将不会。编译器生成的复制构造函数可以是普通的,也可以是非普通的。在一个普通的复制构造函数中,它执行一个成员级的复制。就这样

一个非平凡的复制构造函数做什么? 在C++中,如果没有定义复制构造函数,编译器会为您这样做。若定义了一个,编译器将不会。编译器生成的复制构造函数可以是普通的,也可以是非普通的。在一个普通的复制构造函数中,它执行一个成员级的复制。就这样,c++,copy-constructor,virtual-functions,C++,Copy Constructor,Virtual Functions,但是,如果有一个虚拟函数,那么复制构造函数是非常重要的。它不能只是一点点地复制 这是我的节目。没有什么特别的。只是想说明我的观点 #include<iostream> using namespace std; class baseClass { public: int var; int* varPtr; const float floatVar; int &intRefVar; baseClass(int value) : var(

但是,如果有一个虚拟函数,那么复制构造函数是非常重要的。它不能只是一点点地复制

这是我的节目。没有什么特别的。只是想说明我的观点

#include<iostream>
using namespace std;

class baseClass
{
public:
    int var;
    int* varPtr;
    const float floatVar;
    int &intRefVar;

    baseClass(int value) : var(value), varPtr(&var), floatVar(value), intRefVar(var)
    {
        cout << "baseClass constructor" << endl;
    }

    baseClass(const baseClass& objToCopy) : var(objToCopy.var), varPtr(&var), floatVar(objToCopy.floatVar), intRefVar(var)
    {
        cout << "baseClass copy constructor" << endl;
    }

    virtual void func()
    {
        cout << "Just a virtual func." << endl;
    }
};

class derivedClass : public baseClass
{
public:
    derivedClass(int value) : baseClass(value)
    {
        cout << "derivedClass constructor" << endl;
    }

    derivedClass(const derivedClass& objToCopy) : baseClass(objToCopy)
    {
        cout << "derivedClass copy constructor" << endl;
    }

    virtual void func()
    {
        cout << "Just another virtual func." << endl;
    }
};


int main(int argc, char** argv)
{
    derivedClass derClassObj1(10);
    derivedClass derClassObj2(derClassObj1);
    return 0;
}
#包括
使用名称空间std;
类基类
{
公众:
int-var;
int*varPtr;
常量浮动变量;
int&intRefVar;
基类(int值):var(value)、varPtr(&var)、floatVar(value)、intRefVar(var)
{

cout我认为最重要的障碍是切片。复制构造函数接受对要复制的对象的
const
引用,并且该引用可能绑定到派生类。如果没有虚拟基,没有
vptr
和非平凡的可复制数据成员,复制构造函数可以实现为>
Foo(const Foo& o) noexcept
{
  std::memcpy(this, &o, sizeof(Foo));
}
因为即使参数绑定到一个从
Foo
派生的对象,它的第一个
sizeof(Foo)
字节将是一个完整的
Foo
对象,后面还有任何其他成员。但是,如果有一个
vptr
,可能是第一个成员,它必须这样实现

Foo(const Foo& o) noexcept
{
  std::memcpy(this, &o, sizeof(Foo));
  this->__vptr = Foo::__vptr;
}
关于你的问题

由于我已经定义了自己的复制构造函数,编译器是否向我的复制构造函数“添加”特殊指令来处理虚拟性

这对于复制构造函数并不特殊。在输入任何构造函数的主体之前,实现将确保构造所有基本对象和任何非平凡数据meber。因此,如果您编写复制构造函数,它将已经看到一个半构造的
*此
对象(对于具有虚拟函数成员的类型,
vptr
设置为当前构造类的类型。强调最后一部分,因为在构造过程中,
vptr
将随着调用各种构造函数而从基本类更改为最派生类

由于存在vptr,非平凡复制构造函数与平凡复制构造函数有何不同

vptr不是从源对象复制的,而是必须初始化为指向目标类的虚拟表。因此,不可能从源到目标直接进行“memcpy”复制

另外,请记住,拥有一个vptr并不是严格的要求,一个兼容的实现可以通过其他方式实现虚拟调度(我不知道这会是什么)。虽然,恕我直言,所有实现都使用这种机制。但无论实现选择哪种方式,都会有一些信息(如vptr)必须以与直接“memcpy”副本不兼容的方式进行设置

为什么不能复制vptr?如果两个对象的类型相同(继承中的级别相同),它们都可以指向相同的vtable,不是吗

这里棘手的问题是您假设“两个对象的类型相同”。这在一般情况下是不正确的。源对象很可能属于其他派生类,因此具有不同的虚拟表指针。另一个(更罕见的)实际问题与跨模块代码有关(在不同的DLL/so文件或可执行文件中),同一类型的两个对象可能使用不同的虚拟表(例如,在某些情况下,这是可能的,而不会破坏ODR,如不同的模板实例化)

但问题是,对于复制构造函数的任何使用,编译器都无法保证从源对象复制vptr并期望它适合目标对象是安全的

由于我已经定义了自己的复制构造函数,编译器是否向我的复制构造函数“添加”特殊指令来处理虚拟性


是的,确实如此。我不记得确切的规范,但基本上要求是,当您点击构造函数主体时,vptr(或用于动态调度的任何其他机制)初始化。这本质上要求编译器在所有用户定义的构造函数中添加代码来隐式初始化vptr。

如果您通过引用进行复制,并且复制切片,则不得复制
vptr
。为什么您关心vptr?它们是一个实现细节。您的实现可能会使用它们,也可能不会使用它们。执行虚拟函数分派的另一种方法包括为每个虚拟函数调用提供一个跳转表,根据实际对象类型选择不同的函数。这将明显低于vtable的效率(在代码量和性能方面)。您认为vptr(或其他)不正确是在调用构造函数之前设置的。它是在调用最派生类的构造函数之后设置的,而最派生类的构造函数又是在所有基类构造函数之后设置的。这就是为什么从构造函数调用虚拟函数不会执行虚拟函数分派。@Rob它是在每个类的构造函数运行时设置的。在构造期间,对象的类型随着其sob对象的构造而“演变”。@Rob我没有说vptr是在调用构造函数之前设置的,我是在构造函数体之前说的。每个类在进入其主体时(以及在构建基类之后)都会将vptr设置为其自己的vtable。最后遇到的构造函数体是来自最派生类的构造函数体,这就是为什么vptr是“固定”的构造函数体。在构造函数中调用虚拟func是完全安全的,它只是不会被分派到最派生类(尚未构造),仅此而已。