zoukankan      html  css  js  c++  java
  • 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 = 也一并禁止掉吧。

  • 相关阅读:
    Spring Boot构建RESTful API与单元测试
    Spring Boot中使用Swagger2构建强大的RESTful API文档
    Intellij IDEA 一些不为人知的技巧
    Spring中@Controller和@RestController之间的区别
    Spring 中的default-lazy-init="true" 和 lazy-init="true"
    SpringMVC处理JSON
    建立一个简单的SpringMVC程序
    SpringMVC处理静态资源
    <mvc:annotation-driven/>与<mvc:default-servlet-handler/>之间的一个问题
    Spring AOP 简单理解
  • 原文地址:https://www.cnblogs.com/hanxinle/p/5510273.html
Copyright © 2011-2022 走看看