这里复制构造函数为什么调用了4次

11111111111111111l 2016-10-26 01:46:53

#include "stdafx.h"
#include<istream>
#include<iostream>
#include<math.h>
using namespace std;

class CPoint
{
private:
int x, y;
public:
CPoint(int i , int j )
{
x = i, y = j; cout << "constructor is used" << endl;
}
CPoint(CPoint &p);
int get_x() {
return x;
}
int get_y() {
return y;
}
};
CPoint::CPoint(CPoint &p)
{
x = p.x;
y = p.y;
cout<< "Cpoint copy constructer is used" << endl;
}
class CDistance
{
private:
CPoint p1, p2;
double dist;
public:
CDistance(CPoint xp1, CPoint xp2);
double get_dist() { return dist; }
};
CDistance::CDistance(CPoint xp1, CPoint xp2) :p1(xp1) ,p2(xp2)
{
cout << "distance constructor is used" << endl;
double x = double(p1.get_x() - p2.get_x());
double y = double(p1.get_y() - p2.get_y());
dist = sqrt(x*x + y*y);

}

int main()
{
CPoint myp1(1, 1), myp2(4, 5);
CDistance myd(myp1, myp2);
cout << "the distance is:" << endl;
cout << myd.get_dist() << endl;
getchar();
return 0;
}


...全文
606 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
11111111111111111l 2016-10-27
  • 打赏
  • 举报
回复
引用 26 楼 qq423399099 的回复:
单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
	
CDistance myd(myp1, myp2);
00E625E0  sub         esp,8  
00E625E3  mov         ecx,esp  
00E625E5  lea         eax,[myp2]  
00E625E8  push        eax  
00E625E9  call        CPoint::CPoint (0E6142Eh)  
00E625EE  sub         esp,8  
00E625F1  mov         ecx,esp  
00E625F3  lea         edx,[myp1]  
00E625F6  push        edx  
00E625F7  call        CPoint::CPoint (0E6142Eh)  
00E625FC  lea         ecx,[myd]  
00E625FF  call        CDistance::CDistance (0E6141Fh)  
call CPoint(0E614142)是什么意思啊?而且没看到子程序啊
paschen 版主 2016-10-27
  • 打赏
  • 举报
回复
引用 23 楼 u013511213 的回复:
引用 18 楼 paschen 的回复:
参数传递是按值传递的话,形参是裸骑的一个复制品,类对象传参时会调用复制构造函数
裸骑的意思是不是指只有一层皮了?而对于衣服之类的必须还得自己买?
楼主现在还在纠结的是什么问题
fefe82 2016-10-27
  • 打赏
  • 举报
回复
引用 28 楼 u013511213 的回复:
[quote=引用 26 楼 qq423399099 的回复:] 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
	
CDistance myd(myp1, myp2);
00E625E0  sub         esp,8  
00E625E3  mov         ecx,esp  
00E625E5  lea         eax,[myp2]  
00E625E8  push        eax  
00E625E9  call        CPoint::CPoint (0E6142Eh)  
00E625EE  sub         esp,8  
00E625F1  mov         ecx,esp  
00E625F3  lea         edx,[myp1]  
00E625F6  push        edx  
00E625F7  call        CPoint::CPoint (0E6142Eh)  
00E625FC  lea         ecx,[myd]  
00E625FF  call        CDistance::CDistance (0E6141Fh)  
call CPoint(0E614142)是什么意思啊?而且没看到子程序啊 [/quote] CPoint 的(某一个)构造
z504750758 2016-10-27
  • 打赏
  • 举报
回复
CDistance::CDistance(CPoint xp1, CPoint xp2) :p1(xp1) ,p2(xp2) 在执行 CDistance myd(myp1, myp2);时, 相当于CPoint xp1 = myp1; CPoint xp2 = myp2;复制了两次; 如果CDistance::CDistance(CPoint &xp1, CPoint &xp2) :p1(xp1) ,p2(xp2) 的话就只有两次了,不会有四次了。
JohnHealy 2016-10-26
  • 打赏
  • 举报
回复

1:从有效参数的函数调用过程考虑,参数必定为直接寻址值或间接寻址值(c/c++里以&,*为标识);
2:编译器方面考虑,,fun(a,b),在c/c++里必定最终转换为直接寻址值,而地址里面的值则通过调用时实参赋予。
3:编译器一些具体编译规则作用,如优化规则.

撸主可以感受下
CDistance(CPoint xp1, CPoint xp2);与CDistance(CPoint xp1, CPoint &xp2); 的打印输出
CDistance myd(myp1, myp2); 与 CDistance myd(CPoint(1,1), myp2); 的打印输出
小灸舞 2016-10-26
  • 打赏
  • 举报
回复
单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
引用 24 楼 fefe82 的回复:
引用 23 楼 u013511213 的回复:
[quote=引用 18 楼 paschen 的回复:] 参数传递是按值传递的话,形参是裸骑的一个复制品,类对象传参时会调用复制构造函数
裸骑的意思是不是指只有一层皮了?而对于衣服之类的必须还得自己买?
这应该是用五笔打错了,应该是“实参”吧,不是“裸骑”[/quote]。。。好吧
fefe82 2016-10-26
  • 打赏
  • 举报
回复
引用 23 楼 u013511213 的回复:
引用 18 楼 paschen 的回复:
参数传递是按值传递的话,形参是裸骑的一个复制品,类对象传参时会调用复制构造函数
裸骑的意思是不是指只有一层皮了?而对于衣服之类的必须还得自己买?
这应该是用五笔打错了,应该是“实参”吧,不是“裸骑”
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
引用 18 楼 paschen 的回复:
参数传递是按值传递的话,形参是裸骑的一个复制品,类对象传参时会调用复制构造函数
裸骑的意思是不是指只有一层皮了?而对于衣服之类的必须还得自己买?
fefe82 2016-10-26
  • 打赏
  • 举报
回复
引用 20 楼 u013511213 的回复:
引用 16 楼 fefe82 的回复:
myp1 myp2 xp1 xp2 p1 p2 是六个不同的对象。xp1 xp2 p1 p2 都是通过拷贝构造构造出来的。
是啊,他们是6个对象,myp1初始化xp1,xp1初始化p1,他们都是同类型的对象,我想问,此时xp1,与p1的私有成员x,y有什么不同。 是不是都是(1,1)(4,5)。如果是那dist直接可以为 dist=(xp1.x^2-xp2.x^2)无需再用xp1,xp2初始化p1,p2了而再用p1,p2的私有成员计算距离
他们的值最终是相同的,但是 xp1 与 p1 的成员没有任何关系。 你觉得无需拷贝,那么你可以使用无需拷贝的变量定义方式(全用引用就不会拷贝)。 现在的这种写法是需要拷贝的。相当于你向编译器说了,这里就是要拷贝,生成的程序当然要拷贝。 这里的“多余”拷贝只是因为程序没写好。
fefe82 2016-10-26
  • 打赏
  • 举报
回复
引用 19 楼 u013511213 的回复:
举个例子,A ,B ,C ,D类,每个类分别有私有成员,a,b,c,d,另外,A是B的成员,B是C的成员,C是D的成员;

D dd(12,5);
C cc(3,dd);
B bb(4,cc);
A aa(5,bb);
A aa2(aa);
aa构造时先要构造bb,,bb先要构造cc,构造dd.最后构造aa. 而aa2构造时仍要和aa是一个过程,而不 是直接从aa这个构造好的对象中复制过来。是不是说明构造函数决定了对象在内存中存储的数据结构,而要访问这种数据结构只能通过各层构造函数寻址。
拷贝构造,就是通过拷贝来构造。一边构造,一边拷贝(复制),这两并不互斥啊 .... 类定义决定类内部的结构,而不是构造函数。
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
引用 16 楼 fefe82 的回复:
myp1 myp2 xp1 xp2 p1 p2 是六个不同的对象。xp1 xp2 p1 p2 都是通过拷贝构造构造出来的。
是啊,他们是6个对象,myp1初始化xp1,xp1初始化p1,他们都是同类型的对象,我想问,此时xp1,与p1的私有成员x,y有什么不同。 是不是都是(1,1)(4,5)。如果是那dist直接可以为 dist=(xp1.x^2-xp2.x^2)无需再用xp1,xp2初始化p1,p2了而再用p1,p2的私有成员计算距离
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
举个例子,A ,B ,C ,D类,每个类分别有私有成员,a,b,c,d,另外,A是B的成员,B是C的成员,C是D的成员;

D dd(12,5);
C cc(3,dd);
B bb(4,cc);
A aa(5,bb);
A aa2(aa);
aa构造时先要构造bb,,bb先要构造cc,构造dd.最后构造aa. 而aa2构造时仍要和aa是一个过程,而不 是直接从aa这个构造好的对象中复制过来。是不是说明构造函数决定了对象在内存中存储的数据结构,而要访问这种数据结构只能通过各层构造函数寻址。
paschen 版主 2016-10-26
  • 打赏
  • 举报
回复
参数传递是按值传递的话,形参是裸骑的一个复制品,类对象传参时会调用复制构造函数
AlbertS 2016-10-26
  • 打赏
  • 举报
回复

CDistance::CDistance(CPoint xp1, CPoint xp2) :p1(xp1) ,p2(xp2)
                    拷贝        拷贝   拷贝     拷贝
还是这个比较靠谱
fefe82 2016-10-26
  • 打赏
  • 举报
回复
引用 14 楼 u013511213 的回复:
引用 12 楼 fefe82 的回复:
myp1 myp2 是实参,xp1 xp2 是形参。
那这就对了,myp1,myp2是实参其目的就是为了初始化形参,我们看看CDistance的构造函数,myp1,myp2这个实参是不是对象?是对象吧.,这个对象是点即CPoint对象中包括了坐标即,x,y即用(1,1)(4,5)初始化的,如果这样就无需再用xp1初始化p1,xp2初始化p2,说明这个对象只是一个空壳子其中的x,y 没有连同对象实参myp1,myp2复制 过来,所以最后传递的实参myp1,myp2根本就不是对象,顶多也就是一个对象的接口,比如对象中的函数之类 的,而对象的私有成员并没有传来,而要另外一次传递才能传过来。
myp1 myp2 xp1 xp2 p1 p2 是六个不同的对象。xp1 xp2 p1 p2 都是通过拷贝构造构造出来的。 ========================================== 你描述已经貌似已经不是 C++ 了 ....
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
或者说传递的就是一个类框架,其中所有需要初始化的成员必须另外在传递,所以如里参数中有嵌套,那也只传框架,每一层只传框架,直到最后一层,再反向一层层实例化,让框架变成私有变量有值的真真对象
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
引用 12 楼 fefe82 的回复:
myp1 myp2 是实参,xp1 xp2 是形参。
那这就对了,myp1,myp2是实参其目的就是为了初始化形参,我们看看CDistance的构造函数,myp1,myp2这个实参是不是对象?是对象吧.,这个对象是点即CPoint对象中包括了坐标即,x,y即用(1,1)(4,5)初始化的,如果这样就无需再用xp1初始化p1,xp2初始化p2,说明这个对象只是一个空壳子其中的x,y 没有连同对象实参myp1,myp2复制 过来,所以最后传递的实参myp1,myp2根本就不是对象,顶多也就是一个对象的接口,比如对象中的函数之类 的,而对象的私有成员并没有传来,而要另外一次传递才能传过来。
11111111111111111l 2016-10-26
  • 打赏
  • 举报
回复
引用 2 楼 qq_28026991 的回复:
赋值给函数参数,值传递就2次 赋值给类变量,又是值传递2次。 总共4次
赋值给变量我知道是(1,1)(4,5),赋值给函数参数的值是什么?是一个未初始化p1,p2的对象吗?
fefe82 2016-10-26
  • 打赏
  • 举报
回复
引用 10 楼 u013511213 的回复:
[quote=引用 8 楼 fefe82 的回复:] [quote=引用 5 楼 u013511213 的回复:] 你说的意思是这二次调用是内外层关系 ,第一次调用的时候,并没有把对像全部复制过来完,而对于第二次才把内层p1,p2复制过来是不是?
没听懂。
主函数中对象已经构造完成了,myp1(1,1),  和myp2(4,5).那第二句为何不直接用这个两个对象进行初始化。还要从头开始一层一层初始化?  
参数传递就是用实参初始化一个形参对象。 想复用你可以把参数声明成引用。
引用
如里把这两个对像myp1,myp2封装成一个对象myp是不是就可以只调用一次myp的复制构造函数就可以了?还要不要出从头开始呢?
你在 myp 的构造你就不调用 myp1 和 myp2 的构造了嘛 ...
引用
如里是按初始化列表那样仍然从头开始,是不是说复制构造函数是浅层复制。一次只能复制一个形参与实参的结合,实参的实参需要再一次复制。
这跟深浅拷贝没关系。深浅拷贝要看你的拷贝构造是咋写的。 “实参的实参”又是什么东东 ...[/quote]对CDistance来说,myp1和myp2不就 是形参,而主函数myp1和myp2又被(1,1)(4,5)初始化了,说明这时传给CDistance的myp1,myp2是初始化后的对象,也就变成实参了啊[/quote] myp1 myp2 是实参,xp1 xp2 是形参。
加载更多回复(11)

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧