C++ 类构造析构深拷贝

Posted 技术笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 = 也一并禁止掉吧。

 

以上是关于C++ 类构造析构深拷贝的主要内容,如果未能解决你的问题,请参考以下文章

C++面试之 类string的构造函数拷贝构造函数和析构函数

C++基础3 类:构造 拷贝 析构函数,

一个完整的C++类应该包含什么?

C++入门(拷贝)构造函数和析构函数

C++入门(拷贝)构造函数和析构函数

c++关于派生类的拷贝构造函数