C++拷贝构造函数 - 小但重要的区别

Eya*_*yal 4 c++ copy-constructor vtable

我无法弄清楚这里发生了什么,认为这是非常奇怪的,并且在了解了我之后认为分享答案的原因对于某个人的时间是有价值的.

所以给出这个简单的代码:

    #include <iostream>
using namespace std;

class Shape {
public:
    int* a;
    Shape(){
        cout<<"Default Shape constructor"<<endl;
        a = new int(8); // default
    }
    Shape(int n){
        a = new int(n);
          cout<<"Shape(n) constructor"<<endl;
    }
    // copy constructor
    Shape(const Shape& s){
        cout<<"Shape copy constructor"<<endl;
        a = new int(*(s.a));
    }
    Shape& operator=(const Shape& s){
        cout<<"Shape operator="<<endl;

        if (&s == (this))
            return (*this);
//      this.clear();
        a = new int(*(s.a));

        return (*this);
    }


      virtual void draw(){
             cout<<"Print Shape the number is "<<*a<<endl;
      };
      virtual ~Shape(){
          delete a;
          cout<<"Shape distructor"<<endl;
      }
};

class Circle : public Shape {
public:
    int b;
  Circle() {
      cout<<"Default Circle constructor"<<endl;
      b=0;
  }
  virtual void draw() {
      cout<<"Printing Circle. The number is "<<b<<endl;
  }
   ~Circle(){
      cout<<"Circle distructor"<<endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

为什么以下两个测试给出了两个不同的答案:

static void test1(){
    Shape shape = Circle() ;
    shape.draw();
}

static void test2(){
    Shape* shape = new Circle() ;
    shape->draw();
            delete shape;
}
Run Code Online (Sandbox Code Playgroud)

好吧,因为我刚刚开始了解虚拟机制,我认为两个测试都会产生相同的结果(打印Circle).虽然这是test2中发生的情况,但在test1中并非如此.

为了理解原因,我写了背景中真正发生的事情.

测试1:1.程序执行" Circle() "行.1.1调用Shape的默认构造函数(因为Circle是从Shape派生的).1.2调用Circle的默认构造函数.

  1. 程序执行" Shape shape = "操作.这实际上调用了Shape的复制构造函数.*在这里你应该注意,复制构造函数不会复制_vptr,它是Circle中不可见的字段.它只复制a的值并返回(*this).这是它不打印Circle的真正原因.

我在这里有另一个问题.当运行test1时我得到了这个输出: 默认形状构造函数默认圆构造函数形状复制构造函数圆形析构函数形状析构函数打印形状数字是8形状析构函数

如果拷贝构造函数签名形状(const的形状&S) ,根据该输出,有一个叫真正创建之前拷贝构造函数形状形状.怎么会发生这种情况?

测试2:1.正在堆上构建一个新的Circle类实例.(执行新的循环行)2.返回指向堆内存中该地址的指针并将其放置在指针形状中.在该地址的前四个字节中是指向Circle的虚拟表的指针.这就是test1与test2不同的原因.

重要的是要理解测试之间的区别与test1在堆栈上构建Circle并且test2在堆上构建Circle这一事实无关.嗯,实际上它与它有关.但真正的原因是复制构造函数不复制_vptr.

seh*_*ehe 7

它通过将(非多态)复制到基类型来称为"切片"类

请参阅使用C++思考后台编辑器


Jam*_*lis 6

Shape shape = Circle();
Run Code Online (Sandbox Code Playgroud)

这里没有赋值,因此没有调用赋值运算符.这里=使用的是初始化.然后Circle创建一个临时对象,Circle()然后将其Shape临时对象的一部分复制到其中shape.然后销毁临时对象,因为不再需要它.

Shape* shape = new Circle();
Run Code Online (Sandbox Code Playgroud)

Circle对象是动态创建的(在堆),并返回一个指向该对象.该shape指针指向Shape该部分Circle对象."vptr没有被复制"不是造成差异的原因,这是一种影响.你已经编写了两个测试,它们做了两件完全不同的事情,所以你得到了完全不同的结果."不同的vptr"仅仅是一个不同的结果.

在使用C++进行编程时,您几乎不需要担心像"vptr"这样的低级实现细节以及相关的事情.应该可以在语言级别推断代码,并且在调查性能和调试最棘手的问题时只关注实现细节.