• C++ 类、构造析构、深拷贝


    1st,感性理解类的思想,就是把数据和对数据的操作打包在一块儿,设计类的时候要 想好数据部分和 要进行的操作。以下是时间类的示意,时间包含时分秒,Time为构造函数,该类支持的操作就是设置时间和读取时间,static类型记录对象数量,static机制查询相关书籍。

    //Time.h
    #ifndef Time_h
    #define Time_h
    
    class Time {
    public:
        Time(int h = 0, int m = 0, int s = 0);
        void SetTime(int, int, int);
        void printMilitary( );           //Military style  
        void printStandard( );           //Standard style 
        ~Time();
        static int count;
    private:
        int hour;         //0-23
        int minute;       //0-59
        int second;       //0-59
    };
    #endif // Time_h
    
    //Time.cpp
    #include  <iostream>
    #include  "time.h"
    using namespace std;
    
    int Time::count = 0;
    
    Time::Time(int h, int m, int s) {
    
        count++;
        hour = h; minute = m; second = s;
    }  //Time
    
    Time::~Time() {
        count--;
        cout << "~Time is called." << endl;
    }  //~Time
    
    void Time::SetTime(int h, int m, int s) {
        hour = ((h >= 0 && h < 24) ? h : 0);
        minute = ((m >= 0 && m < 60) ? m : 0);
        second = ((s >= 0 && s < 60) ? s : 0);
    }   //SetTime
    
    void Time::printMilitary() {
    
        cout << (hour < 10 ? "0" : "") << hour << ":"
            << (minute < 10 ? "0" : "") << minute << ":"
            << (second < 10 ? "0" : "") << second << endl;
        return;
    }
    
    void Time::printStandard() {
        cout << ((hour == 0 || hour == 12) ? 12 : hour % 12) << ":"
            << ((minute < 10) ? "0" : "") << minute << ":"
            << ((second < 10) ? "0" : "") << second
            << ((hour < 12) ? "AM" : "PM") << endl;
        return;
    }
    
    //main.cpp
    #include "time.h"
    
    int main() {
        Time a(23,23,12);
        Time b(4, 32, 7);
    
        a.printMilitary();
        a.printStandard();
        b.printMilitary();
        b.printStandard();
    
    
        return 0;
    }
    

    2nd,构造函数和析构函数,以下代码可以准确示意析构函数调用的时机,觉得不够详细还可以自己继续加入cout语句输出信息。

    这个代码的大意就是:class myClass 中还有类型为 classA、classB的数据,它们以初始化列表形式赋值,构造函数调用顺序:ABC,析构函数调用顺序CBA。构造函数分配了内存,析构函数中要记得释放内存。

    /***********************************************
    Class A Constructor !  x=0
    Class B Constructor !  x=0
    Class C Constructor !
    Class C Destructor !
    Class B Destructor !
    Class A Destructor !
    
    
    Class A Constructor !  x=3
    Class B Constructor !  x=3
    Class C Constructor ! With Initial List
    
    
    Class A Constructor !  x=22
    Class B Constructor !  x=65
    Class C Constructor ! With Initial List
    
    
    Class C Destructor !
    Class B Destructor !
    Class A Destructor !
    Class C Destructor !
    Class B Destructor !
    Class A Destructor !
    请按任意键继续. . .
    
    ************************************************/
    
    
    //ClassA.h
    
    #if _MSC_VER >1000
    #pragma once
    #endif   //
    
    class classA {
    public:
        classA(int = 0);
        virtual ~classA();
    };
    
    //classA.cpp
    #include "classA.h"
    #include <iostream>
    using namespace std;
    
    classA::classA(int x) {
        cout << "Class A Constructor !  x=" << x << endl;
    }
    
    classA::~classA() {
        cout << "Class A Destructor !" << endl;
    }
    
    //classB.h
    
    #if _MSC_VER >1000
    #pragma once
    #endif   //
    
    class classB {
    public:
        classB(int = 0);
        virtual ~classB();
    };
    
    //classB.cpp
    #include "classB.h"
    #include <iostream>
    using namespace std;
    
    classB::classB(int x) {
        cout << "Class B Constructor !  x=" << x << endl;
    }
    
    classB::~classB() {
        cout << "Class B Destructor !" << endl;
    }
    
    //myClass.h
    #include "classA.h"
    #include "classB.h"
    
    #if _MSC_VER >1000
    #pragma once
    #endif   //
    
    class myClass {
    public:
        myClass(int);
        myClass();
        myClass(int, int, int);
        virtual ~myClass();
    private:
        int year;
        classA objA;                               //Constructor Turn:A -> B ->C;
        classB objB;
    };
    
    //myClass.cpp
    #include "myClass.h"
    
    #include<iostream>
    using namespace std;
    
    myClass::myClass(int y) {
        cout << "Class C Constructor !" << endl;
        year = y;
    }
    
    myClass::myClass():objA(3),objB(3) {
        cout << "Class C Constructor ! With Initial List" << endl;
    }
    
    myClass::myClass(int y, int a, int b):year(y),objA(a),objB(b) {
        cout << "Class C Constructor ! With Initial List" << endl;
    
    }
    
    myClass::~myClass() {
        cout << "Class C Destructor !" << endl;
    }
    
    //main.cpp
    #include "myClass.h"
    #include<iostream> 
    int main() {
        myClass * pmyobj;
        pmyobj = new myClass(1900);
    
        delete pmyobj;
    
        std::cout << std::endl << std::endl;
    
        myClass myobj;
        std::cout << std::endl << std::endl;
        
        myClass myobj2(2014, 65, 22);
        std::cout << std::endl << std::endl;
        return 0;
    }

    3rd,拷贝构造函数,首先意识到有系统会有默认拷贝构造函数存在,就像有默认的构造函数和析构函数一样。本科时候用VC 6.0编程,拷贝构造函数和operator = 必须要自己定义,尤其是构造函数中有new 的情况。刚刚用了VS2015试了一个程序,发现默认的拷贝构造函数在值类型时传递的是拷贝的值,而对于char * ,则与原对象的值共享,如果析构了原对象,会引发错误(野指针),debug assertion failed,所以还是要自己定义拷贝构造函数。这里谈下浅拷贝和深拷贝。浅拷贝一句话:不涉及内存分配,传递值类型。深拷贝:要分配内存复制值。

    这是浅拷贝 - 用默认拷贝构造函数,会有错误的。

    //myClass.h
    
    #if _MSR_VER > 1000
    #pragma once
    #endif 
    
    #include <string>
    
    class myClass {
    public:
        myClass(char * = NULL, int = 1900);
        void print();
        ~myClass();
    private:
        char * name;
        int year;
    };
    
    //myClass.cpp
    
    #include "myClass.h"
    #include <iostream>
    using namespace std;
    
    myClass::myClass(char *n, int y)  {
        year = y; name = NULL;
        if (n) {
            int len = strlen(n) + 1;
            name = new char[len];
            strcpy_s(name, len, n);
        }
    }  //myClass
    
    myClass::~myClass() {
        if (name) delete  []  name;
    }  //~myClass
    
    void myClass::print() {
        cout << name << "--" << year << endl;
    }
    
    //main.cpp
    
    #include "myClass.h"
    #include<iostream> 
    using namespace std;
    
    int main() {
        int a = 1992, b(a);
        myClass sd1("ABC", a), sd2("XYZ", b + 1);
    
        myClass sd3(sd1);                             //
        sd1.print();
        sd2.print();

    return 0; }

    深拷贝代码如下,加入进去就不会有错误。

    //myClass.h
    
    class myClass {
    public:
               myClass(const myClass & a);
    };   //class myClass
    
    //myClass.cpp
    
    myClass::myClass(const myClass & a) {
        year = a.year; name = NULL;
        if (a.name)  {
            int tmplen = strlen(a.name) + 1;
            name = new char[tmplen];
            strcpy_s(name, tmplen, a.name);
        }
    }
    
    //main.cpp
    int a = 1992, b(a);
    myClass sd1("ABC", a);
    myClass sd2(sd1);      //deep copy!
    sd1.print();
    sd2.print();

    深拷贝函数与类名相同,参数类型为对象的引用,看作是特殊的构造函数吧,注意,并不是所有类都要定义拷贝构造函数,例如网络链接中,同时,此时,operator = 也一并禁止掉吧。

  • 相关阅读:
    Python3之random模块常用方法
    Go语言学习笔记(九)之数组
    Go语言学习笔记之简单的几个排序
    Go语言学习笔记(八)
    Python3之logging模块
    Go语言学习笔记(六)
    123. Best Time to Buy and Sell Stock III(js)
    122. Best Time to Buy and Sell Stock II(js)
    121. Best Time to Buy and Sell Stock(js)
    120. Triangle(js)
  • 原文地址:https://www.cnblogs.com/hanxinle/p/5510273.html
Copyright © 2020-2023  润新知