C++学习笔记_06 深拷贝和浅拷贝 2021-04-19

简介: C++学习笔记_06 深拷贝和浅拷贝 2021-04-19
//C++学习笔记_06  深拷贝和浅拷贝
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
void TestString()
{
    char szName[12];
    char *pName;
    //szName 的值不能改变,它的值,是栈内存的地址
    //szName = "Jack"; //不允许这样赋值
    strcpy(szName,"Jack"); //遇到 '\0' 结束拷贝
    //memcpy(szName, "Jack", 12);  //准确的拷贝 12个字节,不管里面什么内容    
    pName = "Lucy";  //这个是允许的
    pName++; //===> pName 指向 "Lucy" 中的 'u'
    //szName++; //szName 存储的是函数调用栈内, 那段字符串的首地址,不可以修改
    char *p = szName; //这个就是简单的赋值,把szName 的值(地址) 赋值给 p
    string s1 = "Kary";
    string s2 = s1;
    string sss(100, 'a');
    cout << "sss:" << endl;
    cout << "size  :" << sss.size() << endl;
    cout << "sizeof:" << sizeof(sss) << endl;
}
class AAA
{
private:
    char szName[12]; //szName 存储的是栈内存的地址,这段地址长度是 12个字节
    char *pInfo;     //pInfo  没有赋值,指向的地址未知
public:
    AAA(){
        memset(szName, 0, 12);
        pInfo = NULL;
    }
    void SetName(char *pStr) {strcpy(szName, pStr);}
    void SetInfo(char *pStr) { pInfo = pStr;}
  //把私有成员的指针,指向了一个外部地址。
    //这是一个错误的写法,非常危险,可能导致访问或者修改了别人的内存
    //在外部 new 一片内存进行赋值 --》释放内存的时候,不能不释放,也不能多释放
    void ToUpper(){
        char *p=szName;
        while (*p) {//这个退出条件就是 *p==0 ('\0')
            if (*p>='a' && *p<='z')(*p)-=32;                
            p++;
        }
        p=pInfo;
        while (*p) {//这个退出条件就是 *p==0 ('\0')
            if (*p>='a' && *p<='z')(*p)-=32;
            p++;
        }
    }
    void PrintName() { cout << "Name:" << szName << endl;}
    void PrintInfo() { cout << "Info:" << pInfo << endl;}
};
void TestAAA()
{
    AAA A1;
    AAA A2;
    AAA A3;
    char szName[] = "Lucy";
    A1.SetName("Jack");
    A1.SetInfo(szName);
    A2 = A1; //这个拷贝方式:直接把成员变量的内存值复制过来
    //相当于  memcpy(&A2, &A1, sizeof(AAA));
    szName[0] = 'Q';
    cout << "A1:" << endl;
    A1.PrintName();
    A1.PrintInfo();
    cout << endl;
    cout << "A2:" << endl;
    A2.PrintName();
    A2.PrintInfo();
    cout << endl;
    A1.ToUpper(); //调用 A1 的成员函数,把 A2 的成员变量改了
    cout << "A1:" << endl;
    A1.PrintName();
    A1.PrintInfo();
    cout << endl;
    cout << "A2:" << endl;
    A2.PrintName();
    A2.PrintInfo();
    cout << endl;
    cout << "外部szName:" << szName << endl;
    return;
}
void ModifyAAA(AAA &A)
{
    char szName[] = "Jerry";
    A.SetInfo(szName);
    return;
}
class BBB
{
private:
    char *pInfo;
public:
    BBB(){
        cout << "构造函数分配内存" << endl;
        pInfo = new char[1000]; //分配内存
        memset(pInfo, 0, 1000);
    }
    BBB(char szInfo[]){
        cout << "构造函数分配内存" << endl;
        pInfo = new char[1000];
        memset(pInfo, 0, 1000);
        strcpy(pInfo,szInfo);
    }
    BBB(const BBB &B)  {//拷贝构造函数, 入参是 BBB 的对象
        cout << "拷贝构造函数分配内存" << endl;
        pInfo = new char[1000];
        strcpy(pInfo,B.pInfo); //把 B 中的数据拷贝过来
    }
    ~BBB() {
        //前面几节课写的类,析构函数都是空的
        //析构函数的用处是释放资源,构造函数里申请了资源,在这里我们要释放掉
        cout << "析构函数释放内存" << endl;
        delete[] pInfo;
    }
    void SetInfo(char szInfo[]){
        strcpy(pInfo,szInfo);
    }
    void Print(){
        cout << pInfo << endl;
    }
};
void TestBBB()
{
    BBB B1("C++面向对象");
    BBB B2 = B1;      //同样的,B1 的值修改了,会导致 B2修改
    BBB B3(B1);       //也是把 B1 赋值给 B3
    //B2 = B1 和 B3(B1) 这两个方法在我们的 BBB 内没有定义
    //系统会给 BBB 生成一个默认的 拷贝函数,操作就是把私有成员赋值过来
    //这种拷贝方式,我们称为  浅拷贝
    //对应的就有 深拷贝:涉及到申请内存的时候,我们自己定义拷贝构造函数
    //                   这个拷贝构造函数, 我们自己申请内存,然后把目标对象的内存地址内的数据拷贝过来
    //string 的拷贝方式就是 深拷贝
    cout << endl;
    cout << "B2:";
    B2.Print();
    cout << endl;
    B1.SetInfo("Hello world!");
    cout << "B1:";
    B1.Print();
    cout << "B2:";
    B2.Print();
    cout << endl;
    //函数退出前,会调用 B1, B2 的析构函数
    //B2 = B1 也就是说 B1,B2 的 pInfo指针,值是一样的,指向同一片内存
    //内存只申请了一次,被两次释放 --》 出错    
}
void PrintString(const string &s){
    cout << s << endl;
}
void TestCopyOnWrite(){
    //事实上,string 这个类使用的拷贝技术更高效:写时拷贝
    //使用 = 赋值的时候,内部指针指向同一片内存
    //只有这片内存被修改的时候,才复制一份出来
    string s1 = "Hello world!";
    string s2 = s1;
    //s1 和 s2 内部内存都是指向一个 "Hello world 字符串"
    //s1.c_str();  //取出了内部字符串的存储地址
    cout << "Addr S1:" << static_cast<const void*>(s1.c_str()) << endl;
    cout << "Addr S2:" << static_cast<const void*>(s2.c_str()) << endl;
    //这里编译器做了处理,s1 和 s2 内部指针指向了不同的地址    
    //写时拷贝:赋值的时候,不会申请新的内存,两个字符串,指向了同一片内存
    //只有 字符串被修改的时候,才会申请新的内存,把数据拷贝完成后再修改
    //s1[0] = 'K';
    PrintString(s1);
    cout << "Addr S1:" << static_cast<const void*>(s1.c_str()) << endl;
    cout << "Addr S2:" << static_cast<const void*>(s2.c_str()) << endl;
}
int main()
{
    //TestString();
    //TestAAA();
    //TestBBB();
    TestCopyOnWrite();
    system("pause");
  return 0;
}
相关文章
|
3月前
|
C++
c++学习笔记07 结构体
C++结构体的详细学习笔记07,涵盖了结构体的定义、使用、数组、指针、嵌套、与函数的交互以及在结构体中使用const的示例和解释。
39 0
|
2月前
|
安全 C语言 C++
C++学习笔记
C++学习笔记
|
3月前
|
C++
c++学习笔记02 运算符
C++学习笔记,介绍了C++中的运算符,包括基本的加减乘除、求模、前后置递增递减、赋值运算符、比较运算符和逻辑运算符的使用及其注意事项。
40 6
|
3月前
|
C++
c++学习笔记01 基本知识与数据类型
C++学习笔记,涵盖了C++中的常量定义、数据类型、变量内存大小计算、基本数据类型(整型、实型、字符型、字符串型、布尔型)以及转义字符的使用。
46 4
|
3月前
|
算法 C++
c++学习笔记04 数组
这篇文章是C++学习笔记4,主题是数组。
43 4
|
3月前
|
C++
【学习笔记】【C/C++】 c++字面值常量
【学习笔记】【C/C++】 c++字面值常量
39 1
|
3月前
|
存储 C++
c++学习笔记05 函数
C++函数使用的详细学习笔记05,包括函数的基本格式、值传递、函数声明、以及如何在不同文件中组织函数代码的示例和技巧。
34 0
c++学习笔记05 函数
|
3月前
|
编译器 C++
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
46 0
|
3月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
40 0
|
3月前
|
C++
c++学习笔记09 引用
C++引用的详细学习笔记,解释了引用的概念、语法、使用注意事项以及引用与变量的关系。
43 0