zoukankan      html  css  js  c++  java
  • 拷贝构造函数[c++]

    拷贝构造函数何时会被调用?

    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
    ",   (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
    ", 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
    ",z,sin(2*PI*z/360.0)); 
    //    result=atan2(y,   x);     //结果返回是弧度
    //    printf("The   arc   tangent   ratio   of   %lf   is   %.1lf
    ",   (y   /   x),   result*180/PI);  
    //    //sin45的结果
    //    printf("sin(%.0f)=%.2lf
    ",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
    ",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 
    ", *pnVar);
    //     printf("%08x 
    ", *pcVar);
    //     printf("%08x 
    ", *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.
    ");    
    }
    
    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 对于拷贝构造函数解释的很详细。

  • 相关阅读:
    BadgeView使用
    设计模式(一)单例模式的七种写法
    Android 之使用LocalBroadcastManager解决BroadcastReceiver安全问题
    AsyncTask源码分析
    Android微信支付—注意事项
    Android微信支付SDK开发
    Android支付宝SDK开发笔记
    onInterceptTouchEvent与onTouchEvent默认返回值
    线程间的通信方式3--Handler
    Android应用程序启动过程(二)分析
  • 原文地址:https://www.cnblogs.com/qiangua/p/3703752.html
Copyright © 2011-2022 走看看