c++ - 非平凡的复制构造函数有什么作用?

标签 c++ copy-constructor virtual-functions

<分区>

在 C++ 中,如果未定义复制构造函数,编译器将为您完成。如果定义了一个,编译器就不会。编译器生成的复制构造函数可以是平凡的或非平凡的。在普通的复制构造函数中,它执行成员复制。就是这样。

但是,如果存在虚函数,则复制构造函数是非平凡的。它不能只是按位复制。

这是我的程序。没有什么特别的。只是为了说明我的观点..

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

在这个程序中,

  1. 我已经定义了一个拷贝构造函数
  2. 我有一个虚函数,所以复制构造函数很重要

这是我的问题:

  1. 由于 vptr 的存在,非平凡的复制构造函数与平凡的复制构造函数有何不同?
  2. 为什么不能复制vptr?如果两个对象的类型相同(继承级别相同),它们都可以指向同一个虚表,不是吗?
  3. 既然我已经定义了自己的复制构造函数,编译器是否会向我的复制构造函数“添加”特殊指令来处理虚拟性?

干杯。

最佳答案

How does a non-trivial copy constructor differ from a trivial one due to the presence of a vptr?

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

此外,请记住,拥有 vptr 并不是严格的要求,兼容的实现可以通过其他方式实现虚拟调度(我不知道那会是什么)。虽然,据我所知,所有实现都使用这种机制。但是无论实现选择哪种方式做事,很明显都会有一些信息,如 vptr,必须以某种方式设置,这与直接的“memcpy”拷贝不兼容。

Why cannot the vptr be copied? If both objects of same type (same level in the inheritance), they both can point to the same vtable, can they not?

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

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

Since I have defined my own copy constructor, does the compiler 'add' special instructions to my copy constructor to handle the virtualness?

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

关于c++ - 非平凡的复制构造函数有什么作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28260322/

相关文章:

c++ - 为什么我的复制构造函数没有被调用?

c++ - 从 lua 脚本中创建一个新的 C++ 对象?

c++ - 为什么当我用 Rcpp 编写时我不需要包含一些我应该包含在纯 C++ 中编写的库?

c++ - 未实现的拷贝构造函数的拷贝赋值

c++ - 避免重复的 C++ 虚拟表查找

c++ - 异常处理+多态,如果异常方法不起作用,在同一个类中不起作用

c++ - 虚函数的开销会随着继承树中类的数量增加而增加吗?

c++ - 指向对象的指针将指向 C++ 中对象范围之外的什么

c++ - decltype(自动),尾随返回类型和 sfinae : can we mix them?

C++0x : Capture By Value for Lambda, 总是一个拷贝?