一. 什么是拷贝构造函数
首先对于普通类型的对象来说,它们之间的复制是很简单的,例如:
- int a = 100;
- int b = a;
而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
下面看一个类对象拷贝的简单例子。
- #include <iostream>
- using namespace std;
- class CExample {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- { a = b;}
- //一般函数
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- int main()
- {
- CExample A(100);
- CExample B = A; //注意这里的对象初始化要调用拷贝构造函数,而非赋值
- B.Show ();
- return 0;
- }
运行程序,屏幕输出100。从以上代码的运行结果可以看出,系统为对象 B 分配了内存并完成了与对象 A 的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
下面举例说明拷贝构造函数的工作过程。
- #include <iostream>
- using namespace std;
- class CExample {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- { a = b;}
- //拷贝构造函数
- CExample(const CExample& C)
- {
- a = C.a;
- }
- //一般函数
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- int main()
- {
- CExample A(100);
- CExample B = A; // CExample B(A); 也是一样的
- B.Show ();
- return 0;
- }
CExample(const CExample& C) 就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的 构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量 。
二. 拷贝构造函数的调用时机
在C++中,下面三种对象需要调用拷贝构造函数!
1. 对象以值传递的方式传入函数参数
- class CExample
- {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- {
- a = b;
- cout<<"creat: "<<a<<endl;
- }
- //拷贝构造
- CExample(const CExample& C)
- {
- a = C.a;
- cout<<"copy"<<endl;
- }
- //析构函数
- ~CExample()
- {
- cout<< "delete: "<<a<<endl;
- }
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- //全局函数,传入的是对象
- void g_Fun(CExample C)
- {
- cout<<"test"<<endl;
- }
- int main()
- {
- CExample test(1);
- //传入对象
- g_Fun(test);
- return 0;
- }
调用g_Fun()时,会产生以下几个重要步骤:
(1).test对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
(2).然后调用拷贝构造函数把test的值给C。 整个这两个步骤有点像:CExample C(test);
(3).等g_Fun()执行完后, 析构掉 C 对象。
2. 对象以值传递的方式从函数返回
- class CExample
- {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- {
- a = b;
- }
- //拷贝构造
- CExample(const CExample& C)
- {
- a = C.a;
- cout<<"copy"<<endl;
- }
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- //全局函数
- CExample g_Fun()
- {
- CExample temp(0);
- return temp;
- }
- int main()
- {
- g_Fun();
- return 0;
- }
当g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
3. 对象需要通过另外一个对象进行初始化;
- CExample A(100);
- CExample B = A;
- // CExample B(A);
后两句都会调用拷贝构造函数。
三. 浅拷贝和深拷贝
1. 默认拷贝构造函数
很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:
- Rect::Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- }
当然,以上代码不用我们编写,编译器会为我们自动生成。但是如果认为这样就可以解决对象 的复制问题,那就错了,让我们来考虑以下一段代码:
- class Rect
- {
- public:
- Rect() // 构造函数,计数器加1
- {
- count++;
- }
- ~Rect() // 析构函数,计数器减1
- {
- count--;
- }
- static int getCount() // 返回计数器的值
- {
- return count;
- }
- private:
- int width;
- int height;
- static int count; // 一静态成员做为计数器
- };
- int Rect::count = 0; // 初始化计数器
- int main()
- {
- Rect rect1;
- cout<<"The count of Rect: "<<Rect::getCount()<<endl;
- Rect rect2(rect1); // 使用rect1复制rect2,此时应该有两个对象
- cout<<"The count of Rect: "<<Rect::getCount()<<endl;
- return 0;
- }
这段代码对前面的类,加入了一个静态成员,目的是进行计数。在主函数中,首先创建对象rect1,输出此时的对象个数,然后使用rect1复制出对象rect2,再输出此时的对象个数,按照理解,此时应该有两个对象存在,但实际程序运行时,输出的都是1,反应出只有1个对象。此外,在销毁对象时,由于会调用销毁两个对象,类的析构函数会调用两次,此时的计数器将变为负数。
说白了,就是拷贝构造函数没有处理静态数据成员。
出现这些问题最根本就在于在复制对象时,计数器没有递增,我们重新编写拷贝构造函数,如下:
- class Rect
- {
- public:
- Rect() // 构造函数,计数器加1
- {
- count++;
- }
- Rect(const Rect& r) // 拷贝构造函数
- {
- width = r.width;
- height = r.height;
- count++; // 计数器加1
- }
- ~Rect() // 析构函数,计数器减1
- {
- count--;
- }
- static int getCount() // 返回计数器的值
- {
- return count;
- }
- private:
- int width;
- int height;
- static int count; // 一静态成员做为计数器
- };
2. 浅拷贝
所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了,让我们考虑如下一段代码:
- class Rect
- {
- public:
- Rect() // 构造函数,p指向堆中分配的一空间
- {
- p = new int(100);
- }
- ~Rect() // 析构函数,释放动态分配的空间
- {
- if(p != NULL)
- {
- delete p;
- }
- }
- private:
- int width;
- int height;
- int *p; // 一指针成员
- };
- int main()
- {
- Rect rect1;
- Rect rect2(rect1); // 复制对象
- return 0;
- }
在这段代码运行结束之前,会出现一个运行错误。原因就在于在进行对象复制时,对于动态分配的内容没有进行正确的操作。我们来分析一下:
在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:
在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,这时 rect1.p = rect2.p,也即这两个指针指向了堆里的同一个空间,如下图所示:
当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。
3. 深拷贝
在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理:
- class Rect
- {
- public:
- Rect() // 构造函数,p指向堆中分配的一空间
- {
- p = new int(100);
- }
- Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- p = new int; // 为新对象重新动态分配空间
- *p = *(r.p);
- }
- ~Rect() // 析构函数,释放动态分配的空间
- {
- if(p != NULL)
- {
- delete p;
- }
- }
- private:
- int width;
- int height;
- int *p; // 一指针成员
- };
此时,在完成对象的复制后,内存的一个大致情况如下:
此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。
3. 防止默认拷贝发生
通过对对象复制的分析,我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。
- // 防止按值传递
- class CExample
- {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- {
- a = b;
- cout<<"creat: "<<a<<endl;
- }
- private:
- //拷贝构造,只是声明
- CExample(const CExample& C);
- public:
- ~CExample()
- {
- cout<< "delete: "<<a<<endl;
- }
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- //全局函数
- void g_Fun(CExample C)
- {
- cout<<"test"<<endl;
- }
- int main()
- {
- CExample test(1);
- //g_Fun(test); 按值传递将出错
- return 0;
- }
四. 拷贝构造函数的几个细节
1. 拷贝构造函数里能调用private成员变量吗?
解答:这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时就是一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。
2. 以下函数哪个是拷贝构造函数,为什么?
- X::X(const X&);
- X::X(X);
- X::X(X&, int a=1);
- X::X(X&, int a=1, int b=2);
解答:对于一个类X, 如果一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.
- X::X(const X&); //是拷贝构造函数
- X::X(X&, int=1); //是拷贝构造函数
- X::X(X&, int a=1, int b=2); //当然也是拷贝构造函数
3. 一个类中可以存在多于一个的拷贝构造函数吗?
解答:类中可以存在超过一个拷贝构造函数。
- class X {
- public:
- X(const X&); // const 的拷贝构造
- X(X&); // 非const的拷贝构造
- };
注意,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的 对象实行拷贝初始化.
- class X {
- public:
- X();
- X(X&);
- };
- const X cx;
- X x = cx; // error
如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。
这个默认的参数可能为 X::X(const X&)或 X::X(X&),由编译器根据上下文决定选择哪一个。
版权声明:本文为博主原创文章,未经博主允许不得转载。
-
猜你在找
核心技术类目
- 个人资料
-
- 访问:329953次
- 积分:4418
- 等级:
- 排名:第2978名
- 原创:165篇
- 转载:29篇
- 译文:1篇
- 评论:221条
- 文章搜索
- 博客专栏
STL学习笔记 文章:16篇
阅读:17506
- 文章分类
- 阅读排行
- (90856)
- (14773)
- (8325)
- (6062)
- (4545)
- (4240)
- (4040)
- (3971)
- (3740)
- (3366)
- 评论排行
- (145)
- (7)
- (6)
- (6)
- (3)
- (3)
- (3)
- (3)
- (2)
- (2)
- 推荐文章
- id="ad_frm_2" frameborder="0" scrolling="no" src="http://blog.csdn.net/common/ad.html?t=12&containerId=ad_commend&frmId=ad_frm_2" style="border-width: 0px; overflow: hidden; width: 182px; height: 200px;">
- 最新评论
: 楼主X::X(const X&)或 X::X(X&),X&是什么参数
: X::X(const X&)或 X::X(X&),楼主..X&是什么参数
: 你好,“四、设置与清除断点”clean那里应该写错了,应该改为clear
: 请问下,基于c++的怎么打包成apk啊
: 讲的特别详细,让我搞清楚了一个问题
: 深度了解了复制构造函数,感谢楼主。
: 非常好的帖子,仔细阅读并跟着上机实践,真是受益匪浅,感谢分享,终于深刻理解类的拷贝构造函数了,赞赞 ...
: 不错,写的很详细具体!
: 帝仰大学的?
: 辛苦楼主了.赞一个!不过你的例子应该是在 vs 上面验证的,在 mac 平台下 xcode 编译运行...
一. 什么是拷贝构造函数
首先对于普通类型的对象来说,它们之间的复制是很简单的,例如:
- int a = 100;
- int b = a;
而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
下面看一个类对象拷贝的简单例子。
- #include <iostream>
- using namespace std;
- class CExample {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- { a = b;}
- //一般函数
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- int main()
- {
- CExample A(100);
- CExample B = A; //注意这里的对象初始化要调用拷贝构造函数,而非赋值
- B.Show ();
- return 0;
- }
运行程序,屏幕输出100。从以上代码的运行结果可以看出,系统为对象 B 分配了内存并完成了与对象 A 的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
下面举例说明拷贝构造函数的工作过程。
- #include <iostream>
- using namespace std;
- class CExample {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- { a = b;}
- //拷贝构造函数
- CExample(const CExample& C)
- {
- a = C.a;
- }
- //一般函数
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- int main()
- {
- CExample A(100);
- CExample B = A; // CExample B(A); 也是一样的
- B.Show ();
- return 0;
- }
CExample(const CExample& C) 就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的 构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量 。
二. 拷贝构造函数的调用时机
在C++中,下面三种对象需要调用拷贝构造函数!
1. 对象以值传递的方式传入函数参数
- class CExample
- {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- {
- a = b;
- cout<<"creat: "<<a<<endl;
- }
- //拷贝构造
- CExample(const CExample& C)
- {
- a = C.a;
- cout<<"copy"<<endl;
- }
- //析构函数
- ~CExample()
- {
- cout<< "delete: "<<a<<endl;
- }
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- //全局函数,传入的是对象
- void g_Fun(CExample C)
- {
- cout<<"test"<<endl;
- }
- int main()
- {
- CExample test(1);
- //传入对象
- g_Fun(test);
- return 0;
- }
调用g_Fun()时,会产生以下几个重要步骤:
(1).test对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
(2).然后调用拷贝构造函数把test的值给C。 整个这两个步骤有点像:CExample C(test);
(3).等g_Fun()执行完后, 析构掉 C 对象。
2. 对象以值传递的方式从函数返回
- class CExample
- {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- {
- a = b;
- }
- //拷贝构造
- CExample(const CExample& C)
- {
- a = C.a;
- cout<<"copy"<<endl;
- }
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- //全局函数
- CExample g_Fun()
- {
- CExample temp(0);
- return temp;
- }
- int main()
- {
- g_Fun();
- return 0;
- }
当g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
3. 对象需要通过另外一个对象进行初始化;
- CExample A(100);
- CExample B = A;
- // CExample B(A);
后两句都会调用拷贝构造函数。
三. 浅拷贝和深拷贝
1. 默认拷贝构造函数
很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:
- Rect::Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- }
当然,以上代码不用我们编写,编译器会为我们自动生成。但是如果认为这样就可以解决对象 的复制问题,那就错了,让我们来考虑以下一段代码:
- class Rect
- {
- public:
- Rect() // 构造函数,计数器加1
- {
- count++;
- }
- ~Rect() // 析构函数,计数器减1
- {
- count--;
- }
- static int getCount() // 返回计数器的值
- {
- return count;
- }
- private:
- int width;
- int height;
- static int count; // 一静态成员做为计数器
- };
- int Rect::count = 0; // 初始化计数器
- int main()
- {
- Rect rect1;
- cout<<"The count of Rect: "<<Rect::getCount()<<endl;
- Rect rect2(rect1); // 使用rect1复制rect2,此时应该有两个对象
- cout<<"The count of Rect: "<<Rect::getCount()<<endl;
- return 0;
- }
这段代码对前面的类,加入了一个静态成员,目的是进行计数。在主函数中,首先创建对象rect1,输出此时的对象个数,然后使用rect1复制出对象rect2,再输出此时的对象个数,按照理解,此时应该有两个对象存在,但实际程序运行时,输出的都是1,反应出只有1个对象。此外,在销毁对象时,由于会调用销毁两个对象,类的析构函数会调用两次,此时的计数器将变为负数。
说白了,就是拷贝构造函数没有处理静态数据成员。
出现这些问题最根本就在于在复制对象时,计数器没有递增,我们重新编写拷贝构造函数,如下:
- class Rect
- {
- public:
- Rect() // 构造函数,计数器加1
- {
- count++;
- }
- Rect(const Rect& r) // 拷贝构造函数
- {
- width = r.width;
- height = r.height;
- count++; // 计数器加1
- }
- ~Rect() // 析构函数,计数器减1
- {
- count--;
- }
- static int getCount() // 返回计数器的值
- {
- return count;
- }
- private:
- int width;
- int height;
- static int count; // 一静态成员做为计数器
- };
2. 浅拷贝
所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了,让我们考虑如下一段代码:
- class Rect
- {
- public:
- Rect() // 构造函数,p指向堆中分配的一空间
- {
- p = new int(100);
- }
- ~Rect() // 析构函数,释放动态分配的空间
- {
- if(p != NULL)
- {
- delete p;
- }
- }
- private:
- int width;
- int height;
- int *p; // 一指针成员
- };
- int main()
- {
- Rect rect1;
- Rect rect2(rect1); // 复制对象
- return 0;
- }
在这段代码运行结束之前,会出现一个运行错误。原因就在于在进行对象复制时,对于动态分配的内容没有进行正确的操作。我们来分析一下:
在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:
在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,这时 rect1.p = rect2.p,也即这两个指针指向了堆里的同一个空间,如下图所示:
当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。
3. 深拷贝
在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理:
- class Rect
- {
- public:
- Rect() // 构造函数,p指向堆中分配的一空间
- {
- p = new int(100);
- }
- Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- p = new int; // 为新对象重新动态分配空间
- *p = *(r.p);
- }
- ~Rect() // 析构函数,释放动态分配的空间
- {
- if(p != NULL)
- {
- delete p;
- }
- }
- private:
- int width;
- int height;
- int *p; // 一指针成员
- };
此时,在完成对象的复制后,内存的一个大致情况如下:
此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。
3. 防止默认拷贝发生
通过对对象复制的分析,我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。
- // 防止按值传递
- class CExample
- {
- private:
- int a;
- public:
- //构造函数
- CExample(int b)
- {
- a = b;
- cout<<"creat: "<<a<<endl;
- }
- private:
- //拷贝构造,只是声明
- CExample(const CExample& C);
- public:
- ~CExample()
- {
- cout<< "delete: "<<a<<endl;
- }
- void Show ()
- {
- cout<<a<<endl;
- }
- };
- //全局函数
- void g_Fun(CExample C)
- {
- cout<<"test"<<endl;
- }
- int main()
- {
- CExample test(1);
- //g_Fun(test); 按值传递将出错
- return 0;
- }
四. 拷贝构造函数的几个细节
1. 拷贝构造函数里能调用private成员变量吗?
解答:这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时就是一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。
2. 以下函数哪个是拷贝构造函数,为什么?
- X::X(const X&);
- X::X(X);
- X::X(X&, int a=1);
- X::X(X&, int a=1, int b=2);
解答:对于一个类X, 如果一个构造函数的第一个参数是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.
- X::X(const X&); //是拷贝构造函数
- X::X(X&, int=1); //是拷贝构造函数
- X::X(X&, int a=1, int b=2); //当然也是拷贝构造函数
3. 一个类中可以存在多于一个的拷贝构造函数吗?
解答:类中可以存在超过一个拷贝构造函数。
- class X {
- public:
- X(const X&); // const 的拷贝构造
- X(X&); // 非const的拷贝构造
- };
注意,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的 对象实行拷贝初始化.
- class X {
- public:
- X();
- X(X&);
- };
- const X cx;
- X x = cx; // error
如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。
这个默认的参数可能为 X::X(const X&)或 X::X(X&),由编译器根据上下文决定选择哪一个。
版权声明:本文为博主原创文章,未经博主允许不得转载。
-
猜你在找
-
123楼
iamtyk 2015-06-21 08:13发表
-
-
楼主
X::X(const X&)或 X::X(X&),
X&是什么参数
-
122楼
iamtyk 2015-06-21 08:12发表
-
-
X::X(const X&)或 X::X(X&),
楼主..X&是什么参数
-
121楼
zhengjingsen 2015-06-03 11:12发表
-
- 讲的特别详细,让我搞清楚了一个问题
-
120楼
yinglinghuang888888 2015-06-03 10:54发表
-
- 深度了解了复制构造函数,感谢楼主。
-
119楼
BGY_Bluesky 2015-05-28 15:32发表
-
- 非常好的帖子,仔细阅读并跟着上机实践,真是受益匪浅,感谢分享,终于深刻理解类的拷贝构造函数了,赞赞 赞
-
118楼
SmilingSunrise 2015-05-13 16:36发表
-
- 不错,写的很详细具体!
-
117楼
veryitman 2015-05-09 22:10发表
-
-
辛苦楼主了.赞一个!
不过你的例子应该是在 vs 上面验证的,在 mac 平台下 xcode 编译运行有点不一样.
-
116楼
Felix_0920 2015-05-08 17:30发表
-
- 请教楼主一个问题,对于用户自定义的类,如果没有默认的无参构造函数,那么编译器是如果生成类的临时变量对象的?
-
115楼
sinat_27624023 2015-04-22 16:36发表
-
- 博主,想请教你一个问题。拷贝构造函数能将一个对象的string类字符串拷贝给另一个对象吗?
-
114楼
CourageK 2015-04-02 09:35发表
-
- 楼主真是太有心了,让好多人都对复制构造函数有了很深入的理解,从此面试此类问题不再纠结了。谢谢你~
-
113楼
编程艺术家 2015-03-29 16:00发表
-
- mark
-
112楼
qszchew 2015-03-17 19:36发表
-
- 讲得真好!以前一直搞不懂的!
-
111楼
li1191863273 2015-02-11 03:04发表
-
- 受教了
-
110楼
mz490848173 2015-02-09 13:45发表
-
- 想问一下 那个 复制构造函数 所复制的函数 是在 堆内存里 吗 还是 栈内存里
-
109楼
小米mimica 2015-01-15 20:21发表
-
- 写的非常详细,也很易于理解!受益匪浅!
-
108楼
jinjinwu 2015-01-14 15:45发表
-
- 看书一直没看懂,博主讲的很清楚啊,
-
107楼
Sungyers 2015-01-10 15:54发表
-
- 博主给力,狂赞!
-
106楼
louObaichu 2015-01-06 15:28发表
-
- mark
-
105楼
ColaWJY 2014-12-16 21:54发表
-
- 给力!Mark了!
-
104楼
Huai-yu 2014-12-04 09:05发表
-
- 支持楼主,赞一个
-
103楼
御弟叔叔 2014-11-29 14:13发表
-
- 赞一个!
-
102楼
_LebronLu_ 2014-11-28 11:16发表
-
- 很详细,佩服!
-
101楼
jyf823691221 2014-11-13 17:00发表
-
- 赞一个 写的太好了 豁然开朗呀
-
100楼
eyeshot_yang33 2014-11-06 10:16发表
-
- 谢谢,看完豁然开朗了!
-
99楼
hityxhvp 2014-11-05 21:48发表
-
- 通读全文,非常感谢!
-
98楼
tandyx 2014-11-03 17:10发表
-
- 很不错, 非常给力。 特地登陆来点赞。 我的密码都试了好多次才登上来。 哈哈。
-
97楼
zhaolianyun 2014-10-26 20:28发表
-
- 真心不错,非常受教!!!
-
96楼
wjwizard 2014-10-23 19:05发表
-
- 赞一个,好贴
-
95楼
eternal_tune 2014-10-14 12:41发表
-
-
CExample B = A; // CExample B(A); 也是一样的
这段代码应该是赋值构造函数(操作符为‘=’)。如果将此代码放在private里面就编译不过:
CExample & operator=(const CExample&);
CExample B(A);此段才是调用的拷贝构造函数 -
- 回复u012844596:正解!
-
Re:
wobushixiaomi 2014-12-31 14:31发表
-
94楼
Sylvernass 2014-10-13 19:21发表
-
- 写的真心很不错,这部分对初学者来说会搞的有点混,但是看了这篇文章,顿时明白了很多,很清晰,不得不来留言点赞
-
93楼
royliu1 2014-10-11 12:54发表
-
- 写得好! 顺便看了下前辈们的讨论,有收获! 谢谢
-
92楼
Edwin404 2014-09-30 16:33发表
-
- 问个问题,为啥“2. 对象以值传递的方式从函数返回”这个标题下面那个例子什么都没有打印呢?
-
91楼
lichangyu2011 2014-09-29 10:05发表
-
- 转载了!学知识真应该这样,受教了!惭愧一个!!!
-
90楼
puppylpg 2014-09-18 20:09发表
-
- 太详细了!果断赞起!
-
89楼
terry_o0o 2014-09-17 16:37发表
-
- 一直不太理解,就找到lz这个文章了,豁然开朗!
-
88楼
jiaqingmin1990 2014-09-15 10:50发表
-
- nice....
-
87楼
wangxm1111 2014-09-14 16:49发表
-
- 一下子思路很清晰,讲的很不错
-
86楼
图像配准菜鸟 2014-09-13 10:36发表
-
- 受教了!谢谢你耐心的讲解!
-
85楼
他们叫我周周周 2014-09-12 14:09发表
-
- 太棒了~
-
84楼
忆之独秀 2014-09-06 16:16发表
-
- 写的不能更好
-
83楼
贪睡的萝卜 2014-09-05 16:43发表
-
- 受益匪浅,感谢博主
-
82楼
叶子399 2014-09-02 11:03发表
-
- 大赞~
-
81楼
旭梦1990 2014-08-25 08:44发表
-
- 太好了,了解了拷贝构造函数
-
80楼
uiong8163 2014-08-09 00:38发表
-
- 大神,很感谢!
-
79楼
panjunnn 2014-08-07 14:47发表
-
- 受教了,好啊
-
78楼
坚决不做程序狗 2014-08-07 08:48发表
-
- 牛逼。。。。学习了
-
77楼
PushFang 2014-07-30 22:36发表
-
- 大赞!!!!
-
76楼
笃志近思 2014-07-25 17:16发表
-
- 受教了,写的非常棒!
-
75楼
bin03 2014-07-21 11:30发表
-
- 很好。条理清晰。
-
74楼
某种意境 2014-07-09 23:16发表
-
- 终于晓得这玩意儿了
-
73楼
junjie58msp 2014-07-02 11:08发表
-
- 此文写的太好了。赞一个。
-
72楼
HUASHUIXIAOHAI 2014-06-27 14:49发表
-
- 楼主写的真心不错,大赞!
-
71楼
xanarry 2014-06-19 09:12发表
-
- 受益不浅,谢谢博主
-
70楼
卿笃军 2014-05-25 08:47发表
-
-
拷贝构造函数:
A(A a){}
值传递传参为什么会编译通不过? -
- 回复u012339743:这个不是复制构造函数
-
- 回复fupacker:我只是想问这种传参方式 编译为何通不过。
-
-
回复u012339743:编译不通过是因为A a这里的定义问题,只有在看到一个类的定义的时候才能把一个数据成员声明为这个类型的对象,
但是当一个类的类头被看到时,它就被视为已经被声明了,所以一个类可以用指向自身类型的指针或引用作为数据成员
这里数据成员你也可以认为是一个变量的定义 看看C++ primer -
-
回复fupacker:这个我明白。就像结构体一样:
struct node
{
struct node next; //错误
};
struct node
{
struct node *next; //正确
};
————————————
但是:
class A
{
public:
A(A a); //错误
void Print(A a){};//正确
};
这个是如何解释? -
- 回复u012339743:如果不是引用会造成无限递归, (会无限的调用拷贝构造函数)
-
- 回复u012339743:拷贝构造函数一定要使用引用传递 你查一下就知道了
-
Re:
heipacker 2014-06-04 23:11发表
-
Re:
卿笃军 2014-06-05 22:18发表
-
Re:
heipacker 2014-06-06 23:11发表
-
Re:
卿笃军 2014-06-07 00:25发表
-
Re:
gdouse1093 2014-09-28 22:02发表
-
Re:
heipacker 2014-06-07 13:45发表
-
69楼
动感蚂蚁 2014-05-15 13:03发表
-
- 学习了,谢谢
-
68楼
tian15134549098 2014-04-21 20:41发表
-
- 超级给力,赞
-
67楼
lvjing2 2014-04-20 10:52发表
-
- 必须赞一个!
-
66楼
吉米芽菜 2014-03-30 10:49发表
-
- 衷心地赞一个
-
65楼
松木 2014-03-23 18:06发表
-
- 楼主分析得太好了,让我对拷贝构造函数有了更深的认识,赞!
-
64楼
雨中奔跑 2014-02-17 11:55发表
-
- 很详细nice
-
63楼
loe 2013-12-30 17:27发表
-
- mark!
-
62楼
feierfeierfly 2013-12-25 16:20发表
-
- 受教了!谢谢楼主!
-
61楼
无之念 2013-12-23 17:13发表
-
- 受教了
-
60楼
chuyuanjie123 2013-12-16 22:14发表
-
- 很好。思路清晰
-
59楼
曾是土木人 2013-12-15 00:19发表
-
- 总结的很好
-
58楼
lcjwxd 2013-12-05 15:39发表
-
- 初学者也来赞一个,以后好好学习,天天向上!
-
57楼
zzqq0103 2013-12-04 17:20发表
-
- 真的说的很好,受教了!!
-
56楼
苍原狮啸 2013-11-27 11:58发表
-
- 后文的添加的内容很给力
-
55楼
HXD974287503 2013-11-21 16:17发表
-
- 好好!
-
54楼
virginia-qing 2013-11-21 14:29发表
-
- good
-
53楼
zhw_CZ 2013-11-20 22:59发表
-
- 写的真好,谢谢。
-
52楼
yulu27 2013-11-11 16:37发表
-
- 写的真不错
-
51楼
tyy_ing 2013-11-10 20:58发表
-
- 写的很棒 怒赞
-
50楼
code_feng 2013-11-05 15:29发表
-
- 学习了……谢谢楼主~
-
49楼
黑白尤文 2013-08-31 09:16发表
-
- 请问文章中的图是用的什么工具画的啊?
-
- 回复juvenfan:这么强大。。。 我用visio画出来的图都很丑……
-
- 回复juvenfan:visio就可以啊
-
Re:
黑白尤文 2013-09-14 22:34发表
-
Re:
faith19871023 2013-09-07 15:34发表
-
48楼
chz429 2013-08-25 16:06发表
-
-
先赞一个~
关于对象以值传递的方式从函数返回会调用拷贝构造函数,怎么在Devc++测试的时候从函数返回不会调用拷贝构造函数,而在Visual Stdio却调用了呢
- #include<iostream>
- using namespace std;
- struct Node
- {
- int a, b;
- Node(int i, int j):a(i), b(j){}
- Node(const Node& a)
- {
- cout << "copy" << endl;
- }
- };
- Node fun()
- {
- Node n = Node(1,2);
- return n;
- }
- int main()
- {
- fun();
- system("pause");
- }
-
- 回复chz429:g++ 3.2 以上版本对编译器做了优化,导致第三种值返回的情况不调用拷贝构造函数, mac 上也不会调用, vs2012 仍调用,
-
Re:
whyisyoung 2014-11-25 23:05发表
-
47楼
lmnlkm 2013-08-22 16:18发表
-
- 受教了,谢谢
-
46楼
鸭梨小乖宝宝 2013-08-15 18:35发表
-
- 非常好的一篇文章,清晰又有条理
-
45楼
夏雪冬日 2013-08-10 14:48发表
-
- 写的简单、清晰。还不错!
-
44楼
a429051366 2013-08-06 12:40发表
-
- 真心希望楼主能写一本关于c++的书 ,业界的书可谓汗牛充栋,讲的明白清楚的寥若晨星,大部分的书都是讲讲语法,再贴上几个例子,看的人似懂非懂,云里雾里,整本书好像条理清楚,脉络清晰其实一塌糊涂,外国人的书又好点,可是看外文的大部头真的要耐心的,能说的这么清楚明白太难得了,真心希望楼主写本书 ,不写语法什么的 ,就和论坛里面的这种一样,真心的牛啊,要能给做几个c++的视频就更好了,赞一个
-
43楼
wsb929 2013-08-04 21:10发表
-
- 顶 受教了 !! 谢谢!!!
-
42楼
五月初五 2013-08-03 11:53发表
-
- 很好,受教了
-
41楼
云亦无心 2013-07-26 15:58发表
-
- 讲的很有条理,分析透彻~
-
40楼
xiaominglang 2013-07-24 16:33发表
-
- 受教了!!!楼主大牛!!!
-
39楼
__JacHan 2013-07-23 08:23发表
-
- 学习啦,顶哥们,用的时候才能发现问题,有问题了再来跟哥们讨论
-
38楼
4unreal 2013-07-06 16:08发表
-
- 很赞的文章
-
37楼
wennuan80 2013-06-25 09:24发表
-
-
本人菜鸟,想问一下:
拷贝构造函数这样写行吗?
//拷贝构造函数
CExample(const CExample *C)
{
a = C->a;
}
-
36楼
wennuan80 2013-06-25 09:03发表
-
- 为什么要用引用,指针不行吗?
-
35楼
MFCclassxiao 2013-06-18 10:25发表
-
- 学习了,思路清晰了很多,谢谢大牛
-
34楼
wanhuatong1987 2013-06-14 10:02发表
-
-
- Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- p = new int; // 为新对象重新动态分配空间
- *p = *(r.p);
- }
这样写在程序结束的时候调用了两次析构函数,不存在33楼说的内存泄露问题,这是用VS2010调试的结果。
-
33楼
MrSimp1e 2013-06-03 15:08发表
-
-
深拷贝这里,
Rect(const Rect& r)
{
width = r.width;
height = r.height;
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
}
P重新分配了动态空间,但是原来的空间却没有释放掉。这样就造成了内存泄露吧。
Rect(const Rect& r)
{
width = r.width;
height = r.height;
int *pTemp = p; // 将p指针指向的内存地址缓存起来
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
delete pTemp; // 释放p原来的内存
}
只是探讨,没有其他意思。 -
-
这样写的程序中,不会内存泄漏,但是另外一个问题,如果申请空间失败,但之前改变你实例中的部分,因为这里width = r.width; height = r.height; 已经执行了,是不是违反了异常安全性,这个怎么看? -
- 回复bboyfeiyu:博友,你这样写的话会出现“ 0xC0000005: Access violation reading location 0xccccccc0.”错误,这是VS2010调试的结果。其实,文中那样写在退出程序的时候会调用两次析构函数,不会存在内存泄漏的问题。如有不对的地方,请指教。
-
-
回复wanhuatong1987:gcc倒是不会报错,改成这样应该没有问题。
P重新分配了动态空间,但是原来的空间却没有释放掉。这样就造成了内存泄露吧。
Rect(const Rect& r)
{
width = r.width;
height = r.height;
int *pTemp = p; // 将p指针指向的内存地址缓存起来,局部指针变量
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
} -
-
回复bboyfeiyu:我认为不会出现内存泄露。
首先既然是构造函数,p最初就是一个野值,没有指向分配的内存,所以无需考虑释放原来的内存,直接进行内存分配即可。注意是直接分配不是重新分配。
反而觉得您的代码有问题,delete了一个野值,可能会出现问题。
-
Re:
Atlas 2013-06-18 09:28发表
-
Re:
wanhuatong1987 2013-06-14 10:09发表
-
Re:
MrSimp1e 2013-06-14 12:46发表
-
Re:
kkkwjx 2014-09-06 12:35发表
-
32楼
LTheMiracle 2013-05-10 10:10发表
-
- 挺有用的,谢谢!
-
31楼
蛋疼的 2013-04-22 15:20发表
-
- 除非返回值的临时变量是在函数刚进入时先入栈。。
-
- 回复u010050719:从汇编上来说确实如此。临时变量XXX生成的汇编语句是更靠前的。
-
Re:
NBHH0329 2014-07-25 16:57发表
-
30楼
蛋疼的 2013-04-22 15:16发表
-
-
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
个人觉得先析构xxxx对象再析构temp局部变量
函数返回值如果大于8字节,就要创建一个临时内存来放临时变量,按照堆栈的先进后出原则,temp应该是先入栈,xxxx这个临时变量(其实只能叫做指针,指向一块存放该类型变量的内存)后入栈,这个指针指向的地址会存放在寄存器中,函数返回时寄存器EAX根据这个地址去找到临时变量的内容,你也许会说那函数返回,该函数的堆栈祯已经销毁,如何返回该临时变量的值,堆栈祯是被销毁了,但是程序不会清空其中的值,临时变量所在内存值依然存在。 -
- 回复u010050719:你自己分析的结论也是先析构的temp再析构XXX啊
-
- 回复u010050719:本人亲测的确是先析构掉了函数内的局部变量,然后程序执行完后才析构函数返回时调用拷贝构造函数产生的临时对象。
-
- 回复u010050719:分析的到位。我的观点跟你一样!
-
Re:
heipacker 2014-06-06 23:23发表
-
Re:
江浙沪小团队移动外包 2013-10-11 15:34发表
-
Re:
夏雪冬日 2013-08-10 14:46发表
-
29楼
蛋疼的 2013-04-22 15:03发表
-
-
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
第三和第四是不是顺序反了?先析构xxxx对象再析构temp对象
-
28楼
chaoguo1234 2013-04-18 16:26发表
-
- 很好,不错
-
27楼
chm626905227 2013-04-12 17:28发表
-
- 很好的一篇学习拷贝构造函数的文章,顶一个~
-
26楼
曦花 2013-04-08 13:50发表
-
-
为什么要加const?
为什么要用引用?指针行吗?
-
25楼
hulaquandequan 2013-04-07 16:15发表
-
- 真心不错~ 感谢~
-
24楼
hubi 2013-03-22 16:10发表
-
- 棒!!!!!!!!!
-
23楼
jackielzjn 2013-03-14 14:42发表
-
- 谢谢楼主,高手就是不一样。顶一个。。。。。。。
-
22楼
jouyouwen 2013-03-10 16:51发表
-
- 写的很好,受教了,谢谢!
-
21楼
FranklinLING 2013-03-08 20:32发表
-
- 哈哈,和其它评论有同感:简单、透彻!多谢!!
-
20楼
她大哥 2013-03-04 14:51发表
-
- 写的太好了
-
19楼
waldobear 2013-03-02 18:14发表
-
- 很清楚,收获不小。
-
18楼
na_nalove_huahua 2013-02-22 18:25发表
-
- 文章写的很棒 解答了我很多疑惑
-
17楼
fly2sky 2013-02-21 23:11发表
-
- 2中的问题又验证了一下,在vc下就会调用拷贝构造函数,在linux下用g++编译则不会调用拷贝构造函数,看来和编译器有关,文章很给力,学习了
-
16楼
fly2sky 2013-02-21 22:48发表
-
- 2. 对象以值传递的方式从函数返回 这个给的例子验证了一下,并没有调用到拷贝构造函数,请博主试一下
-
15楼
Ritter_Liu 2013-02-19 20:03发表
-
- 此文写的太好了
-
14楼
青茶柠檬 2013-01-30 14:36发表
-
- 谢谢楼主,讲的很清楚。转走了
-
13楼
skkks 2013-01-20 10:21发表
-
- 条理很清晰,喜欢这样的风格,谢谢~~
-
12楼
GrimRaider 2013-01-09 11:22发表
-
- I like it! Thank you!
-
11楼
windyrain999 2012-12-23 12:19发表
-
- 谢谢您,对我很有帮助!!!
-
10楼
nashouat 2012-12-22 10:07发表
-
- 太好了,讲得很通俗易懂,很容易理解,谢谢楼主,真的感谢!现在对拷贝构造函数清晰多了。谢谢!
-
9楼
_北方的雪_ 2012-12-19 11:05发表
-
- 对(四)中第一个问题也是有疑问:在拷贝构造函数中,形参是对象的引用,在函数体中怎么可以直接用对象调用私有成员呢?
-
- 回复sgs1018:拷贝构造函数是一种特殊的构造函数。类的成员函数是可以访问该类的private成员的。
-
Re:
夏雪冬日 2013-08-10 14:43发表
-
8楼
yintangzengli 2012-12-05 09:52发表
-
- 写的蛮不错的,例子有对比,真的是让我看进去了的。
-
7楼
zhengtong0416 2012-11-17 11:40发表
-
- 受教!向您学习
-
6楼
lwbeyond 2012-10-26 13:06发表
-
- 共同进步啊
-
5楼
LinuxMan 2012-10-24 09:16发表
-
- 很容易理解,赞一个
-
4楼
骑着乌龟去看海 2012-10-24 09:00发表
-
- MK
-
3楼
hanzhijun58 2012-10-15 20:25发表
-
- 受教了
-
2楼
MyLend 2012-10-05 22:01发表
-
- 牛啊。。。
-
1楼
aoshikang 2011-04-21 16:53发表
-
- 哥们,你这篇文章真给力!受教了!谢谢。
核心技术类目
- 个人资料
-
- 访问:329953次
- 积分:4418
- 等级:
- 排名:第2978名
- 原创:165篇
- 转载:29篇
- 译文:1篇
- 评论:221条
- 文章搜索
- 博客专栏
STL学习笔记 文章:16篇
阅读:17506
- 文章分类
- 阅读排行
- (90856)
- (14773)
- (8325)
- (6062)
- (4545)
- (4240)
- (4040)
- (3971)
- (3740)
- (3366)
- 评论排行
- (145)
- (7)
- (6)
- (6)
- (3)
- (3)
- (3)
- (3)
- (2)
- (2)
- 推荐文章
- id="ad_frm_2" frameborder="0" scrolling="no" src="http://blog.csdn.net/common/ad.html?t=12&containerId=ad_commend&frmId=ad_frm_2" style="border-width: 0px; overflow: hidden; width: 182px; height: 200px;">
- 最新评论
: 楼主X::X(const X&)或 X::X(X&),X&是什么参数
: X::X(const X&)或 X::X(X&),楼主..X&是什么参数
: 你好,“四、设置与清除断点”clean那里应该写错了,应该改为clear
: 请问下,基于c++的怎么打包成apk啊
: 讲的特别详细,让我搞清楚了一个问题
: 深度了解了复制构造函数,感谢楼主。
: 非常好的帖子,仔细阅读并跟着上机实践,真是受益匪浅,感谢分享,终于深刻理解类的拷贝构造函数了,赞赞 ...
: 不错,写的很详细具体!
: 帝仰大学的?
: 辛苦楼主了.赞一个!不过你的例子应该是在 vs 上面验证的,在 mac 平台下 xcode 编译运行...
123楼 iamtyk 2015-06-21 08:13发表 [回复]-
-
楼主
X::X(const X&)或 X::X(X&),
X&是什么参数
122楼 iamtyk 2015-06-21 08:12发表 [回复]-
-
X::X(const X&)或 X::X(X&),
楼主..X&是什么参数
121楼 zhengjingsen 2015-06-03 11:12发表 [回复]-
-
讲的特别详细,让我搞清楚了一个问题
120楼 yinglinghuang888888 2015-06-03 10:54发表 [回复]-
-
深度了解了复制构造函数,感谢楼主。
119楼 BGY_Bluesky 2015-05-28 15:32发表 [回复]-
-
非常好的帖子,仔细阅读并跟着上机实践,真是受益匪浅,感谢分享,终于深刻理解类的拷贝构造函数了,赞赞 赞
118楼 SmilingSunrise 2015-05-13 16:36发表 [回复]-
-
不错,写的很详细具体!
117楼 veryitman 2015-05-09 22:10发表 [回复]-
-
辛苦楼主了.赞一个!
不过你的例子应该是在 vs 上面验证的,在 mac 平台下 xcode 编译运行有点不一样.
116楼 Felix_0920 2015-05-08 17:30发表 [回复]-
-
请教楼主一个问题,对于用户自定义的类,如果没有默认的无参构造函数,那么编译器是如果生成类的临时变量对象的?
115楼 sinat_27624023 2015-04-22 16:36发表 [回复]-
-
博主,想请教你一个问题。拷贝构造函数能将一个对象的string类字符串拷贝给另一个对象吗?
114楼 CourageK 2015-04-02 09:35发表 [回复]-
-
楼主真是太有心了,让好多人都对复制构造函数有了很深入的理解,从此面试此类问题不再纠结了。谢谢你~
113楼 编程艺术家 2015-03-29 16:00发表 [回复]-
-
mark
112楼 qszchew 2015-03-17 19:36发表 [回复]-
-
讲得真好!以前一直搞不懂的!
111楼 li1191863273 2015-02-11 03:04发表 [回复]-
-
受教了
110楼 mz490848173 2015-02-09 13:45发表 [回复]-
-
想问一下 那个 复制构造函数 所复制的函数 是在 堆内存里 吗 还是 栈内存里
109楼 小米mimica 2015-01-15 20:21发表 [回复]-
-
写的非常详细,也很易于理解!受益匪浅!
108楼 jinjinwu 2015-01-14 15:45发表 [回复]-
-
看书一直没看懂,博主讲的很清楚啊,
107楼 Sungyers 2015-01-10 15:54发表 [回复]-
-
博主给力,狂赞!
106楼 louObaichu 2015-01-06 15:28发表 [回复]-
-
mark
105楼 ColaWJY 2014-12-16 21:54发表 [回复]-
-
给力!Mark了!
104楼 Huai-yu 2014-12-04 09:05发表 [回复]-
-
支持楼主,赞一个
103楼 御弟叔叔 2014-11-29 14:13发表 [回复]-
-
赞一个!
102楼 _LebronLu_ 2014-11-28 11:16发表 [回复]-
-
很详细,佩服!
101楼 jyf823691221 2014-11-13 17:00发表 [回复]-
-
赞一个 写的太好了 豁然开朗呀
100楼 eyeshot_yang33 2014-11-06 10:16发表 [回复]-
-
谢谢,看完豁然开朗了!
99楼 hityxhvp 2014-11-05 21:48发表 [回复]-
-
通读全文,非常感谢!
98楼 tandyx 2014-11-03 17:10发表 [回复]-
-
很不错, 非常给力。 特地登陆来点赞。 我的密码都试了好多次才登上来。 哈哈。
97楼 zhaolianyun 2014-10-26 20:28发表 [回复]-
-
真心不错,非常受教!!!
96楼 wjwizard 2014-10-23 19:05发表 [回复]-
-
赞一个,好贴
95楼 eternal_tune 2014-10-14 12:41发表 [回复]-
-
CExample B = A; // CExample B(A); 也是一样的
这段代码应该是赋值构造函数(操作符为‘=’)。如果将此代码放在private里面就编译不过:
CExample & operator=(const CExample&);
CExample B(A);此段才是调用的拷贝构造函数
Re: wobushixiaomi 2014-12-31 14:31发表 [回复]-
-
回复u012844596:正解!
94楼 Sylvernass 2014-10-13 19:21发表 [回复]-
-
写的真心很不错,这部分对初学者来说会搞的有点混,但是看了这篇文章,顿时明白了很多,很清晰,不得不来留言点赞
93楼 royliu1 2014-10-11 12:54发表 [回复]-
-
写得好! 顺便看了下前辈们的讨论,有收获! 谢谢
92楼 Edwin404 2014-09-30 16:33发表 [回复]-
-
问个问题,为啥“2. 对象以值传递的方式从函数返回”这个标题下面那个例子什么都没有打印呢?
91楼 lichangyu2011 2014-09-29 10:05发表 [回复]-
-
转载了!学知识真应该这样,受教了!惭愧一个!!!
90楼 puppylpg 2014-09-18 20:09发表 [回复]-
-
太详细了!果断赞起!
89楼 terry_o0o 2014-09-17 16:37发表 [回复]-
-
一直不太理解,就找到lz这个文章了,豁然开朗!
88楼 jiaqingmin1990 2014-09-15 10:50发表 [回复]-
-
nice....
87楼 wangxm1111 2014-09-14 16:49发表 [回复]-
-
一下子思路很清晰,讲的很不错
86楼 图像配准菜鸟 2014-09-13 10:36发表 [回复]-
-
受教了!谢谢你耐心的讲解!
85楼 他们叫我周周周 2014-09-12 14:09发表 [回复]-
-
太棒了~
84楼 忆之独秀 2014-09-06 16:16发表 [回复]-
-
写的不能更好
83楼 贪睡的萝卜 2014-09-05 16:43发表 [回复]-
-
受益匪浅,感谢博主
82楼 叶子399 2014-09-02 11:03发表 [回复]-
-
大赞~
81楼 旭梦1990 2014-08-25 08:44发表 [回复]-
-
太好了,了解了拷贝构造函数
80楼 uiong8163 2014-08-09 00:38发表 [回复]-
-
大神,很感谢!
79楼 panjunnn 2014-08-07 14:47发表 [回复]-
-
受教了,好啊
78楼 坚决不做程序狗 2014-08-07 08:48发表 [回复]-
-
牛逼。。。。学习了
77楼 PushFang 2014-07-30 22:36发表 [回复]-
-
大赞!!!!
76楼 笃志近思 2014-07-25 17:16发表 [回复]-
-
受教了,写的非常棒!
75楼 bin03 2014-07-21 11:30发表 [回复]-
-
很好。条理清晰。
74楼 某种意境 2014-07-09 23:16发表 [回复]-
-
终于晓得这玩意儿了
73楼 junjie58msp 2014-07-02 11:08发表 [回复]-
-
此文写的太好了。赞一个。
72楼 HUASHUIXIAOHAI 2014-06-27 14:49发表 [回复]-
-
楼主写的真心不错,大赞!
71楼 xanarry 2014-06-19 09:12发表 [回复]-
-
受益不浅,谢谢博主
70楼 卿笃军 2014-05-25 08:47发表 [回复]-
-
拷贝构造函数:
A(A a){}
值传递传参为什么会编译通不过?
Re: heipacker 2014-06-04 23:11发表 [回复]-
-
回复u012339743:这个不是复制构造函数
Re: 卿笃军 2014-06-05 22:18发表 [回复]-
-
回复fupacker:我只是想问这种传参方式 编译为何通不过。
Re: heipacker 2014-06-06 23:11发表 [回复]-
-
回复u012339743:编译不通过是因为A a这里的定义问题,只有在看到一个类的定义的时候才能把一个数据成员声明为这个类型的对象,
但是当一个类的类头被看到时,它就被视为已经被声明了,所以一个类可以用指向自身类型的指针或引用作为数据成员
这里数据成员你也可以认为是一个变量的定义 看看C++ primer
Re: 卿笃军 2014-06-07 00:25发表 [回复]-
-
回复fupacker:这个我明白。就像结构体一样:
struct node
{
struct node next; //错误
};
struct node
{
struct node *next; //正确
};
————————————
但是:
class A
{
public:
A(A a); //错误
void Print(A a){};//正确
};
这个是如何解释?
Re: gdouse1093 2014-09-28 22:02发表 [回复]-
-
回复u012339743:如果不是引用会造成无限递归, (会无限的调用拷贝构造函数)
Re: heipacker 2014-06-07 13:45发表 [回复]-
-
回复u012339743:拷贝构造函数一定要使用引用传递 你查一下就知道了
Re: 卿笃军 2014-06-07 14:55发表 [回复]-
-
回复fupacker:这个我查过,也明白A(A a)这样会带来的问题。
就是上面那个问题有些不明白。
Re: 小王王小 2014-08-04 16:37发表 [回复]-
-
回复u012339743:拷贝构造函数如果允许值传递,那么实参对象传递给形参对象,会拥有两个存储空间,新创建的临时存储空间对象初始化时,同样需要调用拷贝构造函数,以此类推,会永无休止的调用拷贝构造函数,最终会导致栈溢出。
Re: 卿笃军 2014-09-28 23:42发表 [回复]-
-
回复wangyong19881123:我明白了。
69楼 动感蚂蚁 2014-05-15 13:03发表 [回复]-
-
学习了,谢谢
68楼 tian15134549098 2014-04-21 20:41发表 [回复]-
-
超级给力,赞
67楼 lvjing2 2014-04-20 10:52发表 [回复]-
-
必须赞一个!
66楼 吉米芽菜 2014-03-30 10:49发表 [回复]-
-
衷心地赞一个
65楼 松木 2014-03-23 18:06发表 [回复]-
-
楼主分析得太好了,让我对拷贝构造函数有了更深的认识,赞!
64楼 雨中奔跑 2014-02-17 11:55发表 [回复]-
-
很详细nice
63楼 loe 2013-12-30 17:27发表 [回复]-
-
mark!
62楼 feierfeierfly 2013-12-25 16:20发表 [回复]-
-
受教了!谢谢楼主!
61楼 无之念 2013-12-23 17:13发表 [回复]-
-
受教了
60楼 chuyuanjie123 2013-12-16 22:14发表 [回复]-
-
很好。思路清晰
59楼 曾是土木人 2013-12-15 00:19发表 [回复]-
-
总结的很好
58楼 lcjwxd 2013-12-05 15:39发表 [回复]-
-
初学者也来赞一个,以后好好学习,天天向上!
57楼 zzqq0103 2013-12-04 17:20发表 [回复]-
-
真的说的很好,受教了!!
56楼 苍原狮啸 2013-11-27 11:58发表 [回复]-
-
后文的添加的内容很给力
55楼 HXD974287503 2013-11-21 16:17发表 [回复]-
-
好好!
54楼 virginia-qing 2013-11-21 14:29发表 [回复]-
-
good
53楼 zhw_CZ 2013-11-20 22:59发表 [回复]-
-
写的真好,谢谢。
52楼 yulu27 2013-11-11 16:37发表 [回复]-
-
写的真不错
51楼 tyy_ing 2013-11-10 20:58发表 [回复]-
-
写的很棒 怒赞
50楼 code_feng 2013-11-05 15:29发表 [回复]-
-
学习了……谢谢楼主~
49楼 黑白尤文 2013-08-31 09:16发表 [回复]-
-
请问文章中的图是用的什么工具画的啊?
Re: 黑白尤文 2013-09-14 22:34发表 [回复]-
-
回复juvenfan:这么强大。。。 我用visio画出来的图都很丑……
Re: faith19871023 2013-09-07 15:34发表 [回复]-
-
回复juvenfan:visio就可以啊
48楼 chz429 2013-08-25 16:06发表 [回复]-
-
先赞一个~
[cpp]
view plain
copy
- #include<iostream>
- using namespace std;
- struct Node
- {
- int a, b;
- Node(int i, int j):a(i), b(j){}
- Node(const Node& a)
- {
- cout << "copy" << endl;
- }
- };
- Node fun()
- {
- Node n = Node(1,2);
- return n;
- }
- int main()
- {
- fun();
- system("pause");
- }
关于对象以值传递的方式从函数返回会调用拷贝构造函数,怎么在Devc++测试的时候从函数返回不会调用拷贝构造函数,而在Visual Stdio却调用了呢
Re: whyisyoung 2014-11-25 23:05发表 [回复]-
-
回复chz429:g++ 3.2 以上版本对编译器做了优化,导致第三种值返回的情况不调用拷贝构造函数, mac 上也不会调用, vs2012 仍调用,
47楼 lmnlkm 2013-08-22 16:18发表 [回复]-
-
受教了,谢谢
46楼 鸭梨小乖宝宝 2013-08-15 18:35发表 [回复]-
-
非常好的一篇文章,清晰又有条理
45楼 夏雪冬日 2013-08-10 14:48发表 [回复]-
-
写的简单、清晰。还不错!
44楼 a429051366 2013-08-06 12:40发表 [回复]-
-
真心希望楼主能写一本关于c++的书 ,业界的书可谓汗牛充栋,讲的明白清楚的寥若晨星,大部分的书都是讲讲语法,再贴上几个例子,看的人似懂非懂,云里雾里,整本书好像条理清楚,脉络清晰其实一塌糊涂,外国人的书又好点,可是看外文的大部头真的要耐心的,能说的这么清楚明白太难得了,真心希望楼主写本书 ,不写语法什么的 ,就和论坛里面的这种一样,真心的牛啊,要能给做几个c++的视频就更好了,赞一个
43楼 wsb929 2013-08-04 21:10发表 [回复]-
-
顶 受教了 !! 谢谢!!!
42楼 五月初五 2013-08-03 11:53发表 [回复]-
-
很好,受教了
41楼 云亦无心 2013-07-26 15:58发表 [回复]-
-
讲的很有条理,分析透彻~
40楼 xiaominglang 2013-07-24 16:33发表 [回复]-
-
受教了!!!楼主大牛!!!
39楼 __JacHan 2013-07-23 08:23发表 [回复]-
-
学习啦,顶哥们,用的时候才能发现问题,有问题了再来跟哥们讨论
38楼 4unreal 2013-07-06 16:08发表 [回复]-
-
很赞的文章
37楼 wennuan80 2013-06-25 09:24发表 [回复]-
-
本人菜鸟,想问一下:
拷贝构造函数这样写行吗?
//拷贝构造函数
CExample(const CExample *C)
{
a = C->a;
}
36楼 wennuan80 2013-06-25 09:03发表 [回复]-
-
为什么要用引用,指针不行吗?
35楼 MFCclassxiao 2013-06-18 10:25发表 [回复]-
-
学习了,思路清晰了很多,谢谢大牛
34楼 wanhuatong1987 2013-06-14 10:02发表 [回复]-
-
[cpp]
view plain
copy
- Rect(const Rect& r)
- {
- width = r.width;
- height = r.height;
- p = new int; // 为新对象重新动态分配空间
- *p = *(r.p);
- }
这样写在程序结束的时候调用了两次析构函数,不存在33楼说的内存泄露问题,这是用VS2010调试的结果。
33楼 MrSimp1e 2013-06-03 15:08发表 [回复]-
-
深拷贝这里,
Rect(const Rect& r)
{
width = r.width;
height = r.height;
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
}
P重新分配了动态空间,但是原来的空间却没有释放掉。这样就造成了内存泄露吧。
Rect(const Rect& r)
{
width = r.width;
height = r.height;
int *pTemp = p; // 将p指针指向的内存地址缓存起来
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
delete pTemp; // 释放p原来的内存
}
只是探讨,没有其他意思。
Re: Atlas 2013-06-18 09:28发表 [回复]-
-
这样写的程序中,不会内存泄漏,但是另外一个问题,如果申请空间失败,但之前改变你实例中的部分,因为这里width = r.width; height = r.height; 已经执行了,是不是违反了异常安全性,这个怎么看?
Re: wanhuatong1987 2013-06-14 10:09发表 [回复]-
-
回复bboyfeiyu:博友,你这样写的话会出现“ 0xC0000005: Access violation reading location 0xccccccc0.”错误,这是VS2010调试的结果。其实,文中那样写在退出程序的时候会调用两次析构函数,不会存在内存泄漏的问题。如有不对的地方,请指教。
Re: MrSimp1e 2013-06-14 12:46发表 [回复]-
-
回复wanhuatong1987:gcc倒是不会报错,改成这样应该没有问题。
P重新分配了动态空间,但是原来的空间却没有释放掉。这样就造成了内存泄露吧。
Rect(const Rect& r)
{
width = r.width;
height = r.height;
int *pTemp = p; // 将p指针指向的内存地址缓存起来,局部指针变量
p = new int; // 为新对象重新动态分配空间
*p = *(r.p);
}
Re: kkkwjx 2014-09-06 12:35发表 [回复]-
-
回复bboyfeiyu:我认为不会出现内存泄露。
首先既然是构造函数,p最初就是一个野值,没有指向分配的内存,所以无需考虑释放原来的内存,直接进行内存分配即可。注意是直接分配不是重新分配。
反而觉得您的代码有问题,delete了一个野值,可能会出现问题。
32楼 LTheMiracle 2013-05-10 10:10发表 [回复]-
-
挺有用的,谢谢!
31楼 蛋疼的 2013-04-22 15:20发表 [回复]-
-
除非返回值的临时变量是在函数刚进入时先入栈。。
Re: NBHH0329 2014-07-25 16:57发表 [回复]-
-
回复u010050719:从汇编上来说确实如此。临时变量XXX生成的汇编语句是更靠前的。
30楼 蛋疼的 2013-04-22 15:16发表 [回复]-
-
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
个人觉得先析构xxxx对象再析构temp局部变量
函数返回值如果大于8字节,就要创建一个临时内存来放临时变量,按照堆栈的先进后出原则,temp应该是先入栈,xxxx这个临时变量(其实只能叫做指针,指向一块存放该类型变量的内存)后入栈,这个指针指向的地址会存放在寄存器中,函数返回时寄存器EAX根据这个地址去找到临时变量的内容,你也许会说那函数返回,该函数的堆栈祯已经销毁,如何返回该临时变量的值,堆栈祯是被销毁了,但是程序不会清空其中的值,临时变量所在内存值依然存在。
Re: heipacker 2014-06-06 23:23发表 [回复]-
-
回复u010050719:你自己分析的结论也是先析构的temp再析构XXX啊
Re: 江浙沪小团队移动外包 2013-10-11 15:34发表 [回复]-
-
回复u010050719:本人亲测的确是先析构掉了函数内的局部变量,然后程序执行完后才析构函数返回时调用拷贝构造函数产生的临时对象。
Re: 夏雪冬日 2013-08-10 14:46发表 [回复]-
-
回复u010050719:分析的到位。我的观点跟你一样!
29楼 蛋疼的 2013-04-22 15:03发表 [回复]-
-
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
第三和第四是不是顺序反了?先析构xxxx对象再析构temp对象
28楼 chaoguo1234 2013-04-18 16:26发表 [回复]-
-
很好,不错
27楼 chm626905227 2013-04-12 17:28发表 [回复]-
-
很好的一篇学习拷贝构造函数的文章,顶一个~
26楼 曦花 2013-04-08 13:50发表 [回复]-
-
为什么要加const?
为什么要用引用?指针行吗?
25楼 hulaquandequan 2013-04-07 16:15发表 [回复]-
-
真心不错~ 感谢~
24楼 hubi 2013-03-22 16:10发表 [回复]-
-
棒!!!!!!!!!
23楼 jackielzjn 2013-03-14 14:42发表 [回复]-
-
谢谢楼主,高手就是不一样。顶一个。。。。。。。
22楼 jouyouwen 2013-03-10 16:51发表 [回复]-
-
写的很好,受教了,谢谢!
21楼 FranklinLING 2013-03-08 20:32发表 [回复]-
-
哈哈,和其它评论有同感:简单、透彻!多谢!!
20楼 她大哥 2013-03-04 14:51发表 [回复]-
-
写的太好了
19楼 waldobear 2013-03-02 18:14发表 [回复]-
-
很清楚,收获不小。
18楼 na_nalove_huahua 2013-02-22 18:25发表 [回复]-
-
文章写的很棒 解答了我很多疑惑
17楼 fly2sky 2013-02-21 23:11发表 [回复]-
-
2中的问题又验证了一下,在vc下就会调用拷贝构造函数,在linux下用g++编译则不会调用拷贝构造函数,看来和编译器有关,文章很给力,学习了
16楼 fly2sky 2013-02-21 22:48发表 [回复]-
-
2. 对象以值传递的方式从函数返回 这个给的例子验证了一下,并没有调用到拷贝构造函数,请博主试一下
15楼 Ritter_Liu 2013-02-19 20:03发表 [回复]-
-
此文写的太好了
14楼 青茶柠檬 2013-01-30 14:36发表 [回复]-
-
谢谢楼主,讲的很清楚。转走了
13楼 skkks 2013-01-20 10:21发表 [回复]-
-
条理很清晰,喜欢这样的风格,谢谢~~
12楼 GrimRaider 2013-01-09 11:22发表 [回复]-
-
I like it! Thank you!
11楼 windyrain999 2012-12-23 12:19发表 [回复]-
-
谢谢您,对我很有帮助!!!
10楼 nashouat 2012-12-22 10:07发表 [回复]-
-
太好了,讲得很通俗易懂,很容易理解,谢谢楼主,真的感谢!现在对拷贝构造函数清晰多了。谢谢!
9楼 _北方的雪_ 2012-12-19 11:05发表 [回复]-
-
对(四)中第一个问题也是有疑问:在拷贝构造函数中,形参是对象的引用,在函数体中怎么可以直接用对象调用私有成员呢?
Re: 夏雪冬日 2013-08-10 14:43发表 [回复]-
-
回复sgs1018:拷贝构造函数是一种特殊的构造函数。类的成员函数是可以访问该类的private成员的。
8楼 yintangzengli 2012-12-05 09:52发表 [回复]-
-
写的蛮不错的,例子有对比,真的是让我看进去了的。
7楼 zhengtong0416 2012-11-17 11:40发表 [回复]-
-
受教!向您学习
6楼 lwbeyond 2012-10-26 13:06发表 [回复]-
-
共同进步啊
5楼 LinuxMan 2012-10-24 09:16发表 [回复]-
-
很容易理解,赞一个
4楼 骑着乌龟去看海 2012-10-24 09:00发表 [回复]-
-
MK
3楼 hanzhijun58 2012-10-15 20:25发表 [回复]-
-
受教了
2楼 MyLend 2012-10-05 22:01发表 [回复]-
-
牛啊。。。
1楼 aoshikang 2011-04-21 16:53发表 [回复]-
-
哥们,你这篇文章真给力!受教了!谢谢。