24小时热门版块排行榜    

查看: 1391  |  回复: 14
当前只显示满足指定条件的回帖,点击这里查看本话题的所有回帖

微尘、梦想

木虫 (知名作家)

[求助] 复制构造函数问题

书上说:复制构造函数在以下3种情况下会被调用:
1、用类的对象去初始化该类的另一个对象时;
2、函数的形参是类的对象时;
3、函数的返回值是类的对象时。
程序:
CODE:
#include
using namespace std;
class point
{
private:
        int x,y;
public:
        point(int a=0,int b=0)      //定义构造函数
        {
                x=a;
                y=b;
        }
        point(point &p);            //声明复制构造函数
        int getx()
        { return x; }
        int gety()
        { return y; }
};
point::point(point &p)          //定义复制构造函数
{
        x=p.x*10;
        y=p.y*20;
        cout <<"调用复制构造函数"< }
void f(point p)
{  cout < point g()
{  point q(3,5); return q; }
void main()
{
        point p1(1,2);
        point p2(p1);    //第一种情况
        cout <         f(p2);      //第二种情况
        p2=g();     //第三种情况
        cout < }

问题:该程序在第三种情况时并没有调用复制构造函数,其执行结果为:
调用复制构造函数
10      40
调用复制构造函数
100     800
3       5
不知道为什么,谢谢各位指点!!!
回复此楼
任风云变幻,我笑对人生!
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖

来自天狼

木虫 (正式写手)

★ ★ ★
微尘、梦想(金币+3): 鼓励交流!辛苦了…… 2011-06-20 19:42:37
看了楼主的问题,才知道自己的C++功底不扎实,为了搞明白这个问题,这几天真是寝食难安。查了所有能找到的C++书,还在网上扒了无数网页,加上自己的思考,终于有所收获,虽然已经结贴,但还是想谈谈自己的看法。
    我用的是vs2005,如果在“项目”->“属性”->“配置属性”->“C/C++”中把“优化”禁用(原设置是“完全优化(/0x)”),把main函数中的代码全部屏蔽,只写一个g();则输出为“调用复制构造函数”。用point p3 = g();测试,只输出一行“调用复制构造函数”,这说明g()返回时调用了复制构造函数,这一点容易理解,但是赋值给p3时并没有调用,这一点就不好理解了。
    C++中设置复制构造函数的目的,主要是为了解决用一个对象给另一个对象赋值时的深拷贝问题。楼主的例子中没有用到深拷贝,我们可以假设其中存在深拷贝,不论g()中定义的对象q有没有分配资源,在return时都会调用复制构造函数把q复制到一个临时对象中,临时对象中的资源会重新分配。以point p3 = g();为例,如果=操作符也调用复制构造函数的话,那么这一个语句中就会有三次分配资源的行为,g()中定义的q一次,return给临时对象时一次,把临时对象复制到p3时又一次,如果资源比较大的话,效率会非常低。如果我是编译器的设计者,一定会想办法提高效率,因为临时对象只起到了一个中转的作用,完全没有必要,所以可以直接把g()返回的临时对象返回到p3中。
    为彻底搞清楚编译器都做了什么,只好祭出反汇编大法,单步跟踪point p3 = g();逐条指令硬啃,证明编译器确实只调用了一次复制构造函数,而且是直接把g()的返回值返回到了p3中。单独一个g();也会调用复制构造函数,只不过是把结果返回到栈上的无名空间(对象)中。
    未优化的代码中,point p5 = p3; 的反汇编码跟 point p2(p1); 的反汇编码一模一样。可见编译器是把 point p5 = p3; 当成 point p5(p3); 来处理的。
    以上是禁用优化的情况,如果配置为“完全优化”,那么本例中的point p3 = g();是不会调用复制构造函数的。因为g()只有两条语句,而且没有分配资源,被编译器直接内联了,反汇编码中是直接把g()中定义的q(3,5)赋值给p3的。

    在VC6.0中,同样的代码point p3 = g();在未优化的情况下,会输出两个“调用复制构造函数”,可见不同的编译器对复制构造函数的处理是不同的。

    根据这几天在解决问题过程中的摸索和思考,认识到C++标准虽然定义了许多规范,但是编译器在实现时并没有拘泥于这些条条框框。更是认识到实践是检验真理的唯一标准,尽信书则不如无书。

    以下是两个参考的网页:
复制初始化、复制构造函数、赋值运算符
http://hi.baidu.com/zhenghui1988 ... 3ce020cefca305.html
    标准规定了语义上的确是先用直接构造函数建立一个临时对象,然后调用复制构造函数把临时对象拷贝到正在建立的对象上,但标准允许实 现省略复制拷贝函数(即使复制拷贝函数有副作用)。需要注意的是,GCC编译器仍然会检查标准规定的语义,如果复制构造函数为private时,GCC就 会报错;这点和VC不同,VC不检查该语义,直接省略了复制构造函数。

构造函数,默认构造函数,复制构造函数,赋值构造函数
http://zjayang198861.blog.163.co ... romSearchEngine=yes
12楼2011-06-20 16:28:15
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖
查看全部 15 个回答

libralibra

至尊木虫 (著名写手)

骠骑将军

【答案】应助回帖

★ ★
余泽成(金币+2): 谢谢参与应助! 2011-06-08 16:09:43
微尘、梦想(金币+5): 谢谢~~ 2011-06-09 07:37:32
point g()
.....
p2=g();     //第三种情况
============

第三种情况直接返回了一个point对象,不会调用的
matlab/VB/python/c++/Java写程序请发QQ邮件:790404545@qq.com
2楼2011-06-07 21:36:08
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖

微尘、梦想

木虫 (知名作家)

引用回帖:
Originally posted by libralibra at 2011-06-07 21:36:08:
point g()
.....
p2=g();     //第三种情况
============

第三种情况直接返回了一个point对象,不会调用的

书上是这么说的,然后我去网上查了查也是这么说的啊~~
http://baike.baidu.com/view/2329038.htm
5.何时使用复制构造函数
任风云变幻,我笑对人生!
3楼2011-06-07 21:38:31
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖

libralibra

至尊木虫 (著名写手)

骠骑将军

不过我vs2008编译器有调用啊
CODE:
调用复制构造函数
10      40
调用复制构造函数
100     800
调用复制构造函数
30      100

Process returned 0 (0x0)   execution time : 0.047 s
Press any key to continue.

matlab/VB/python/c++/Java写程序请发QQ邮件:790404545@qq.com
4楼2011-06-07 21:43:57
已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖
信息提示
请填处理意见