拷贝构造函数何时会被调用?
1. 对象以值传递的方式传入函数参数
2.对象以值传递的方式从函数返回
3.对象需要通过另外一个对象进行初始化
下面我们来看代码:
//#include <iostream> //using namespace std; //template <typename T, int MAX> //T:队列的类型,char,int,double,包括自己的struct 。MAX:循环队列的最大长度 //class Queue //{ //private: // T p[MAX];//队列用的数组 // int head, tail;//头尾下标 //public: // //在定义时预处理 // inline Queue() { clear(); } // //预处理过程,使头尾下标都是0 // inline void clear() { head = tail = 0; } // //循环队列压入:把元素压入队列,如果队尾超出了循环队列的最大长度,把队尾下标变成0 // inline void push(const T& n) { p[tail++] = n; if (tail == MAX) tail = 0; } // //循环队列弹出:弹出队头元素,即在现有队列中最先加入的元素。同样使用了循环优化. // inline void pop() { if (++head == MAX) head = 0; } // //函数返回循环队列中的队头元素 // inline T& top() { return p[head]; } // //判断队列是否为空 // inline bool empty() {return head == tail;} //}; // ////定义队列: //Queue <int/* 或者char之类的 */, 11111111/*循环队列的最大长度*/> q; ////在使用时可以直接用q.clear() 清空,q.push(x)压入要加入的元素,x = q.top() 找到队头元素, q.pop()弹出队头元素,q.empty()判队列是否为空 //Queue<char,20> cq; //int main() //{ // int i,n=10; // int x; // int array[10]={0,1,2,3,4,5,6,7,8,9}; // char array_[10]={‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘f‘,‘g‘,‘h‘,‘i‘,‘j‘}; // for(i=0;i<n;i++) // { // cq.push(array_[i]); // } // for(i=0;i<n;i++) // { // cout <<cq.top()<<endl; // cq.pop(); // } // // return 0; //} //函数模板 //template<typename T> #include <stdio.h> #include <math.h> //反正切,知道两对边,求弧度(要自己转化成角度) /*int main(void) { double result; double x = 10.0, y = 10.0; result = atan2(y, x); printf("The arc tangent ratio of %lf is %.1lf\n", (y / x), result*180/3.1415926); return 0; }*/ //#include <stdio.h> //#include <math.h> ////传入的参数为弧度 //int main(void) //{ // double result, x = 0.5; // // result = sin(x); // printf("The sin() of %lf is %lf\n", x, result); // return 0; //} //弧度转化角度:弧度*180/PI //角度转化弧度:角度*PI/180 //#include <math.h> //#include <stdio.h> //const double PI=acos(-1.0); ////sin传入的参数的是弧度 //void main() //{ // int z=30; // double x = 10.0, y = 10.0; // double result; // //sin30结果 // printf("sin(%d)=%.2lf\n",z,sin(2*PI*z/360.0)); // result=atan2(y, x); //结果返回是弧度 // printf("The arc tangent ratio of %lf is %.1lf\n", (y / x), result*180/PI); // //sin45的结果 // printf("sin(%.0f)=%.2lf\n",result*180/PI,sin(result)); //注意不要用%d //} //桶排序思想 //假如要排序的是数字是 2 4 5 5 5 8 8 9 1 1 //#include<stdio.h> //#define length 10 //int main() //{ // //数组元素值全部初始化为0 // int array[length]={0}; // int i,j; // int n; // for(i=0;i<length;i++) // { // scanf("%d",&n); // array[n]++; // } // for (i = 0; i < length; i++) // { // for(j=0;j<array[i];j++) // printf("%d ",i); // } // // return 0; //} // Ba 2 Da 4 Ea 5 Eb 5 Ec 5 Ha 8 Hb 8 Ia 9 Aa 1 Ab 1 //#include<stdio.h> //#define length 10 // //struct node //{ // char country[6]; //国家 // int count; //金牌数 //}; //int main() //{ // int i,j,n; // int array[10][10]={0}; //数组内的元素是结构体索引 // int index[10]={0}; //存储每行队列(数组)内元素个数 // struct node ary[length]={ // {"Ba",2},{"Da",4},{"Ea",5},{"Eb",5}, // {"Ec",5},{"Ha",8},{"Hb",8},{"Ia",9}, // {"Aa",1},{"Ab",1}}; // for(i=0;i<length;i++) // { // n=ary[i].count; //桶子编号 // array[n][index[n]]=i; //存储结构体数组索引 // index[n]++; // } // for(i=0;i<length;i++) // { // for(j=0;j<index[i];j++) // { // printf("%s %d\n",ary[array[i][j]].country,ary[array[i][j]].count); // } // } //} //#include<stdio.h> // //int main() // { // int nVar = 0x12345678; // int *pnVar = &nVar; // char *pcVar = (char*)&nVar; // short *psnVar = (short*)&nVar; // printf("%08x \r\n", *pnVar); // printf("%08x \r\n", *pcVar); // printf("%08x \r\n", *psnVar); // return 0; // } //拷贝构造函数 // 04.cpp : Defines the entry point for the console application. // //#include "stdafx.h" #include "iostream" using namespace std; class CDog { public: unsigned int m_Weight; unsigned int m_Age; CDog(int weight,int age); CDog(int weight = 20); CDog(const CDog & theDog); void SetAge(unsigned int age); int GetAge (); ~CDog(); }; CDog::CDog(int weight,int age) { m_Weight = weight; m_Age = age; } CDog::CDog(int weight) { m_Weight = weight; } CDog::CDog(const CDog & theDog) { m_Weight = theDog.m_Weight; m_Age = theDog.m_Age; printf("Copy constructor is called.\n"); } void CDog::SetAge(unsigned int age) { m_Age = age; } int CDog::GetAge () { return m_Age; } CDog::~CDog() { } CDog CopyData(CDog m_dog) { return m_dog; } void test(CDog tmp) { } CDog test2() { CDog temp; cout<<"对象以值传递的方式从函数返回"<<endl; return temp; } int main(int argc, char* argv[]) { CDog Example; cout<<"对象以值传递的方式传入函数参数"<<endl; test(Example); test2(); //对象需要通过另外一个对象进行初始化 //这里调用的是拷贝构造函数。而不是我们看到的赋值 CDog test3 = Example; return 0; }
浅拷贝与深拷贝
1.浅拷贝指的是只对对象中的数据成员进行简单的赋值。
2.默认拷贝构造函数执行的就是浅拷贝。
3.默认拷贝构造函数不会处理静态数据成员。
4.浅拷贝无法处理对象内的动态成员。
原因:浅拷贝仅仅是赋值,所以拷贝的对象的动态成员与原对象动态成员指向同一块内存,但是析构函数却会调用二次,
释放两次同一块内存,自然会出错。
5.深拷贝会在拷贝函数中为动态成员分配内存。
//代码来自: //http://blog.csdn.net/lwbeyond/article/details/6202256 作者:lwbeyond #include "iostream" using namespace std; 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; }
如果运行此程序,会出错。原因上面已经阐述。
修改成深拷贝:
//代码来自: //http://blog.csdn.net/lwbeyond/article/details/6202256 作者:lwbeyond #include "iostream" using namespace std; class Rect { public: Rect() // 构造函数,p指向堆中分配的一空间 { p = new int(100); } Rect(const Rect& r) { width = r.width; height = r.height; //p = new int(100); // 为新对象重新动态分配空间 p = new int; // 为新对象重新动态分配空间 *p = *(r.p); } ~Rect() // 析构函数,释放动态分配的空间 { if(p != NULL) { delete p; } } private: int width; int height; int *p; // 一指针成员 }; int main() { Rect rect1; Rect rect2(rect1); // 复制对象 return 0; }
成功运行。
避免调用默认拷贝构造函数的方法:
声明一个私有拷贝构造函数。
拷贝构造函数可有一个或者多个。
下面来自博客:http://blog.csdn.net/lwbeyond/article/details/6202256
对于一个类X, 如果一个构造函数的第一个参数是下列之一:
a)
X&
b) const X&
c) volatile
X&
d) const volatile
X&
且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.
http://blog.csdn.net/lwbeyond/article/details/6202256 对于拷贝构造函数解释的很详细。