我无法弄清楚这里发生了什么,认为这很奇怪,在理解了原因后,我认为分享答案对某人的时间很有价值。
所以给出这个简单的代码:
#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;
}
};
为什么以下两个测试给出了两个不同的答案:
static void test1(){
Shape shape = Circle() ;
shape.draw();
}
static void test2(){
Shape* shape = new Circle() ;
shape->draw();
delete shape;
}
好吧,因为我刚刚开始了解虚拟机制,所以我认为这两个测试都会产生相同的结果(打印 Circle)。虽然这是在test2中发生的情况,但在test1 中并非如此。
为了理解原因,我写了幕后真正发生的事情。
Test1: 1. 程序执行“ Circle() ”行。1.1 调用Shape的默认构造函数(因为Circle是从Shape派生的)。1.2 调用了 Circle 的默认构造函数。
- 程序执行“ Shape shape = ”动作。这实际上调用了 Shape 的复制构造函数。*这里你应该注意,复制构造函数不会复制 _vptr ,它是 Circle 中的一个不可见字段。它只复制 a 的值并返回 (*this)。这是它不打印 Circle 的真正原因。
在这里,我确实有另一个问题。当运行 test1 我得到这个输出: Default Shape constructor Default Circle constructor Shape copy constructor Circle disstructor Shape distructor Print Shape the number is 8 Shape distructor
如果复制构造函数签名是Shape(const Shape& s),根据此输出,在实际将形状创建为Shape之前调用复制构造函数。这怎么可能发生?
Test2: 1. 一个新的类 Circle 实例正在堆上构建。(执行new Circle行) 2. 返回指向堆上内存中该地址的指针并放置在指针形状中。在该地址的前四个字节中是指向 Circle 虚拟表的指针。这就是为什么 test1 与 test2 不同的原因。
重要的是要理解测试之间的差异与 test1 在堆栈上构建一个 Circle 而 test2 在堆上构建一个 Circle 的事实无关。好吧,实际上它与它有关。但真正的原因是复制构造函数没有复制_vptr。