/**
 作者: cwl
 内容:
        带指针类的注意点
        c++构造函数,拷贝构造,拷贝赋值
        new delete解析

*/
#include <bits/stdc++.h>

using namespace std;

class String {
public:
    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';
        }
    }

    ///拷贝构造,接受自己这种东西的引用
    String(const String& str) {
        m_data = new char[strlen(str.m_data) + 1];
        strcpy(m_data, str.m_data);
    }

    ///拷贝赋值,接受自己这种东西的引用
    String& operator=(const String &str) {
        if(this == &str) {
            return *this;
        }
        delete[] m_data;
        m_data = new char[strlen(str.m_data) + 1];
        strcpy(m_data, str.m_data);
        return *this;
    }

    ~String() {
        delete[] m_data;
    }

    char* get_c_str() const {
        return m_data;
    }
private:
    char* m_data;
};

inline ostream&
operator << (ostream& os, const String &str) {
    os << str.get_c_str();
    return os;
}

int main() {

    /**
        c++中类四个重要部分
        构造函数
        析构函数
        拷贝构造
        拷贝赋值
    */

    ///[1] 如果你的class如果带着指针,就必须重写拷贝构造和拷贝赋值
    /**
        构造和析构是带指针的类必备的,而容易被忽略的是下面两个部分。

        【1.1】拷贝构造

        String(const String& str) {
            m_data = new char[strlen(str.m_data) + 1];
            strcpy(m_data, str.m_data);
        }
        可能会有疑问,str中的m_data明明是private为什么能直接访问?
        答:解释有很多,其中一个是一个类的不同对象互为友元

        【1.2】拷贝赋值

        String& operator=(const String &str) {
            if(this == &str) {
                return *this;
            }
            delete[] m_data;
            m_data = new char[strlen(str.m_data) + 1];
            strcpy(m_data, str.m_data);
            return *this;
        }

        杀掉原来的,创建一个同大小的空间,返回。
        细节是要检测是否是检测自我赋值。
        if(this == &str) {
            return *this;
        }
        多想一步,加强代码稳定性。


        下面我们添加输出
        inline ostream&
        operator << (ostream& os, const String &str) {
            os << str.get_c_str();
            return os;
        }
    */
    String a = "hello";
    cout << a << endl;

    /**
        堆和栈
        【1】String a("qqq");
                a是栈空间,有操作系统创建在作用域{}结束后释放。
                自动,auto,也就是旧的时候的auto语义,c++11前的
        【2】String *p = new String("asd");
                p在栈空间,执行了new处理的堆空间。需要手动delete
                否则会出现[内存泄漏]
        【3】static int a;
                声明周期扩展被扩张
        【4】全局对象
                生命在main之前,main结束后才析构
    */

    ///【new】new 会先申请内存,转形,然后调用构造函数
    ///new 的过程
    ///注:operator new是一个函数的名字,c++中能查到源代码

    /**
        String *pc;
        void* mem = operator new(sizeof(String));   申请空间
        pc = static_cast<String*>(mem);             类型转化
        pc->String::String("asd");    调用构造函数,直接调会有问题,这里只是示例

    */

    ///【delete】delete的过程
    /// String::~String(ps)     //析构函数
    /// operator delete(ps)     //释放内存

    /**
        new 和 delete 底层使用malloc和delete获得空间

    */

    return 0;
}