【C++侯捷】面对对象高级编程(三)

【C++侯捷】面对对象高级编程(三)

主要内容:拷贝构造、拷贝复制、析构

复习complex的构建过程

头文件的编写

#ifndef __COMPLEX__
#define __COMPLEX__

class complex
{
public:
    //构造函数
    complex(double r = 0,double r = o)
        : re(r), im(r)
        {}
    //成员函数方法
    
private:
    //成员变量
};
#endif

拷贝构造、拷贝复制、析构

class String
{
public:
    String(const char * cstr = 0);
    String(const String & str);             //拷贝构造
    String & operator = (const String& str);//拷贝赋值
    ~String();                              //析构函数
    char* get_c_str() const {return m_data;}//inline funtion 
private:
    char* m_data;
};

string源码分析

inline String::String(const char* cstr = 0)
{
    if(cstr){
        m_data = new char[strlen(cstr)+1];
        strcpy(m_data, cstr);
    }
    else{
        m_data = new char[1];
        *m_data = '\0';
    }
}

inline String::~String()
{
    delete[] m_data;  //清理;动态内存这里需要清理,否则会造成内存泄漏。像之前提到的value则不必。
}

应用

{
    String s1();              //1
    String s2("hellow");      //2   这两个在离开作用域的时候析构函数会自动消逝掉
    String* p = new String("hellow"); //动态创建
    delete p;
}

class with pointer members 必须有copy ctor 和copy op= (拷贝构造、拷贝赋值)

image-20221105213245776

带有指针的类成员函数中必须有拷贝构造和拷贝复制

如果自己不去定义,编译器将默认使用default copy ctor 和 default op=,

会造成一下问题

image-20221105213228561

即,ab只是两个指针,这样会造成b指针和a指针指向同一块内存空间,b原指向的内存空间则成了“孤儿”(内存泄漏),会出现问题,(比如如果将来通过a去更改,则b也会受影响)这也不是我们想要的结果,这样的称为“浅拷贝”。

深拷贝就是copy ctor 和copy op要做的事情。

copy ctor(拷贝构造函数)

inline
String::String(const String& str) //传入
{
    m_data = new char[strlen(str.m_data) + 1];  //先开辟一段存放蓝本的内存空间
    strcpy(m_data, str.m_data);
}

实例

{
	String s1("hellow");  
    String s2(s1);    //以s1为蓝本创建s2
    //String s2 = s1;  //将s1赋值给s2,同时创建s2对象;需调用构造函数
}

copy assignment operator(拷贝赋值函数)

inline
String& String::operator=(const String& str)
{
    if(this == this == &str)
        return *str;                 //检测自我赋值
    delete[] m_data;                //先清空原有
    m_data = new data[strlen(str.m_data) + 1];    //创造相同空间
    strcpy(m_data, str.m_data);
    return *this;
}

实例

{
    String s1("hellow");
    String s2(s1);
    
    s2 = s1;
}

一定要在operator操作中检测是否自我赋值

否则,第一步清空将清空原有的内存空间!!!不只是效率问题。

output函数

#include <iostream>
ostream& operator<<(ostream& os, const String& str)  //全局函数
{
    os << str.get_c_str();
    return os;
}

{
    String s1("hellow ");
    cout << s1;
}

堆,栈与内存管理

所谓stack(栈),所谓heap(堆)

  • Stack,是存在于某作用域(scope)的一块内存空间(memory space)。例如当你调用函数,函数本身即会形成一个stack用来放置它所接收的参数,以及返回地址。在函数本体(function body)内声明的任何变量,其所使用的内存都取自上述stack。

  • Heap,或谓system heap,是指由操作系统提供的一块global内存空间,程序可\(动态分配\)(dynamic allocated)从某中获得若干区块(blocks)。

class Complex{ ...};
...
{
    Complex c1(1,2);    //c1所占用的空间来自stack,随着离开作用空间会自动消逝
    Complex* p = new Complex(3); //此处是个临时对象,可在任何地方动态创建,其所占用的空间仍是以new自heap动态分配而得,并由p指向,需要手动释放
}

stack objects的生命期

上述c1便是所谓stack object,其生命在作用域结束之际结束(调用析构函数),这种作用域内的object,又称为auto object,因为它会被自动清除。

static local objects的生命期

class Complex{ ... };
{
    static Complex c2(1,2);
}

c2便是所谓static object,其生命在作用域结束之后仍然存在,直到整个程序结束。

global objects的生命期

class Complex{... };
...
Complex c3(1,2);
int main()
{
    ...
}

一直有效直至程序结束。可把他视为一种static object。

heap objects的生命期

heap objects的生命期

new: 先分配memory,再调用ctor

image-20221106142900730

delete:先调用dtor,在释放memory

image-20221106143831544

动态分配所得的内存块(memory block),in VC

8.堆,栈与内存管理(30:00)

image-20221106144155926

动态分配所得的array

array new 与array delete

若在动态创建对象是使用的是

{
    m_data= new char[strlen(str)+1];    //使用中括号形式
}

那么在销毁时要使用

{
    deletep[] m_data;
}

不然会出错

详细

image-20221106145844063

3是vc做法,记录array个数,和上面内存分配不一样

array new一定要搭配array delete

image-20221106150643803

posted @ 2023-10-01 18:35  travis-ge  阅读(6)  评论(0编辑  收藏  举报