• [c++] 面向对象课程(二)-- 带指针类的设计


    class with pointer menbers

    string_test.cpp

     1 #include "string.h"
     2 #include <iostream>
     3 
     4 using namespace std;
     5 
     6 int main()
     7 {
     8   String s1("hello"); 
     9   String s2("world");
    10     
    11   String s3(s2);
    12   cout << s3 << endl;
    13   
    14   s3 = s1;
    15   cout << s3 << endl;     
    16   cout << s2 << endl;  
    17   cout << s1 << endl;      
    18 }
    View Code

    string.h

     1 #ifndef __MYSTRING__
     2 #define __MYSTRING__
     3 
     4 class String
     5 {
     6 public:                                 
     7    String(const char* cstr=0);                     
     8    String(const String& str);                    
     9    String& operator=(const String& str);         
    10    ~String();                                    
    11    char* get_c_str() const { return m_data; }
    12 private:
    13    char* m_data;
    14 };
    15 
    16 #include <cstring>
    17 
    18 inline
    19 String::String(const char* cstr)
    20 {
    21    if (cstr) {
    22       m_data = new char[strlen(cstr)+1];
    23       strcpy(m_data, cstr);
    24    }
    25    else {   
    26       m_data = new char[1];
    27       *m_data = '';
    28    }
    29 }
    30 
    31 inline
    32 String::~String()
    33 {
    34    delete[] m_data;
    35 }
    36 
    37 inline
    38 String& String::operator=(const String& str)
    39 {
    40    if (this == &str)
    41       return *this;
    42 
    43    delete[] m_data;
    44    m_data = new char[ strlen(str.m_data) + 1 ];
    45    strcpy(m_data, str.m_data);
    46    return *this;
    47 }
    48 
    49 inline
    50 String::String(const String& str)
    51 {
    52    m_data = new char[ strlen(str.m_data) + 1 ];
    53    strcpy(m_data, str.m_data);
    54 }
    55 
    56 #include <iostream>
    57 using namespace std;
    58 
    59 ostream& operator<<(ostream& os, const String& str)
    60 {
    61    os << str.get_c_str();
    62    return os;
    63 }
    64 
    65 #endif
    View Code

    注意的点

    • string_test.cpp:11拷贝构造,14拷贝赋值
    • string.h:8拷贝构造(构造函数接受自己),9拷贝赋值,10析构函数
    • 不知道将来要创建的对象多大,所以只放一根指针,再动态创建空间放对象
    • 类中带指针,要关注三个特殊函数(Big Three)
    • 结束符号“”判断字符串结束
    • 21判断是否空指针
    • 22:new:,动态分配一块内存
    • 31-35:delete,析构函数,防止内存泄露,变量离开作用域时自动调用
    • 11的get_c_str()是为了配合输出函数

    拷贝构造(copy ctor)

    • String a("Hello"); String b("World"); b = a;
    • 如果没有构造拷贝,会发生b和a的指针都指向“Hello”,“World”没有指针指向,导致内存泄露
    • 而且a、b一个改动会影响另一个,别名在编程中是危险的事
    • 这种拷贝方式称为“浅拷贝”,是编译器的默认版本
    • copy ctor 实现“深拷贝”,创建足够的新空间存放蓝本
    • String s2(s1); 与 String s2 = s1; 效果相同

    拷贝赋值(copy op =)

    • String s1("hello"); String s2(s1); s2 = s1;
    • 过程:43删除左值--44开辟新空间--45拷贝右值
    • 40-41:检测自我赋值(self assignment),来源端和目的端是否相同
    • 这步的意义不只是提高效率,不这样写会出错
    • 因为43会把原空间删掉,导致45行复制的时候访问空指针

     栈(stack)和堆(heap)

    • {Complex c1(1,2);}
    • {Complex* p = new Complex(3);
    • delete p;}
    • stack:存在于某作用域(scope)的一块内存空间,调用函数时,函数本身即形成一个stack用来防止它接受的参数,以及返回地址,离开作用域后,析构函数被自动调用(aoto object)
    • heap:system heap,操作系统提供的一块global内存空间,程序可以动态分配(dynamic allocated)从中获得若干区域,使用完后需手动释放空间
    • {static Complex c1(1,2);}
    • 静态对象,离开作用域后对象仍存在,组用域是整个程序
    • 全局对象,写在任何作用域之外(全局作用域之中),也可看做一种静态对象
    • new:先分配memory,再调用ctor,分解为以下三个函数
    • void* mem = operator new(sizeof(Complex)); // 分配内存,operator new调用malloc(n)
    • p = static_cast<Complex*>(mem); // 转型
    • p->Complex::Complex(1,2); // 构造函数,Complex::Complex(pc,1,2);
    • delete:先调用析构函数,再释放内存
    • String::~String(p); // 把字符串里面动态分配的内存删掉(字符串本身只是指针m_data)
    • operator delete(p); // 内部调用free(p),删掉字符串本身的指针

    new到底分配多少内存

    • 调试模式下加上debug header 32byte,正常模式下中间为数据(一根指针4byte),上下为cookies 2*4byte,凑够16的倍数
    • 动态分配所得的array
    • new []:array new
    • delete[]:array delete
    • array new 一定要搭配 array delete
    • String* p = new String[3]; delete[] p; // 唤起3次dtor
    • String* p = new String[3]; delete p; // 唤起1次dtor,另外2个指针指向的动态内存数据无法删除(注意指针是可以删除的)
    • 虽然new complex的时候不会产生此问题,但也要注意搭配使用,养成好习惯

    参考:

    const在函数前面与后面的区别

    https://blog.csdn.net/qq_25800311/article/details/83054129

  • 相关阅读:
    Java的Regex --正则表达式
    Java的包装类
    类的始祖Object
    abstract和interface关键字介绍
    内部类
    Accumulation Degree [换根dp,二次扫描]
    牛客练习赛61 [口胡]
    CF1334G Substring Search [bitset,乱搞]
    CF1175F The Number of Subpermutations [哈希,乱搞]
    CF793G Oleg and chess [线段树优化建边,扫描线,最大流]
  • 原文地址:https://www.cnblogs.com/cxc1357/p/12285532.html
Copyright © 2020-2023  润新知