【发布时间】:2011-04-11 13:17:48
【问题描述】:
我无法弄清楚这里发生了什么,认为这很奇怪,在理解了原因后,我认为分享答案对某人的时间很有价值。
所以给出这个简单的代码:
#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 中并非如此。
为了理解原因,我在后台写下了真正发生的事情。
测试1: 1. 程序执行“Circle()”行。 1.1 调用Shape的默认构造函数(因为Circle是从Shape派生的)。 1.2 调用Circle的默认构造函数。
- 程序执行动作“Shape shape =”。这实际上调用了 Shape 的复制构造函数。 * 这里你应该注意,复制构造函数不会复制 _vptr ,它是 Circle 中的一个不可见字段。它只复制 a 的值并返回 (*this)。这就是它不打印 Circle 的真正原因。
我还有一个问题。 当运行 test1 我得到这个输出: 默认形状构造函数 默认圆构造函数 形状复制构造函数 圈子析构函数 形状分解器 打印形状数量为 8 形状破坏子
如果复制构造函数签名是Shape(const Shape& s),根据这个输出,在实际创建shape为之前有一个复制构造函数调用形状。 怎么会这样?
测试2: 1. Circle 类的一个新实例正在堆上构建。 (执行 new Circle 行) 2. 指向堆上内存中该地址的指针被返回并放置在指针shape中。在该地址的前四个字节中是指向Circle虚拟表的指针。这就是 test1 与 test2 不同的原因。
重要的是要理解测试之间的差异与 test1 在堆栈上构建一个 Circle 而 test2 在堆上构建一个 Circle 的事实无关。好吧,实际上它与它有关。但真正的原因是拷贝构造函数没有拷贝_vptr。
【问题讨论】:
-
***对不起,我的意思是复制构造函数。
-
想想为什么赋值运算符和复制构造函数之间的区别很重要。现在行为应该很明显了——对新对象的第一次调用是它的构造函数,正如你所期望的那样。
Circle()创建的临时对象与const Shape&类型的参数兼容,因为向上转换是一种隐式转换,因此复制构造函数是最佳匹配。
标签: c++ copy-constructor vtable