美文网首页
Boolan/C++面向对象高级编程 part2

Boolan/C++面向对象高级编程 part2

作者: 我才是helo | 来源:发表于2017-10-29 16:16 被阅读0次

    C++面向对象高级编程 part2

    @(boolan C++)[C++]
    2017-10-22 14:17:56 / helingchao


    概述

    本章节内容主要讲述如何设计class with pointer,以string为例。

    #ifndef __MYSTRING__
    #define __MYSTRING__
    
    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; }
    private:
       char* m_data;
    };
    
    #include <cstring>
    
    inline
    String::String(const char* cstr)
    {
       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;
    }
    
    inline
    String& 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;
    }
    
    inline
    String::String(const String& str)
    {
       m_data = new char[ strlen(str.m_data) + 1 ];
       strcpy(m_data, str.m_data);
    }
    
    #include <iostream>
    using namespace std;
    
    ostream& operator<<(ostream& os, const String& str)
    {
       os << str.get_c_str();
       return os;
    }
    
    #endif
    
    

    big three

    所谓big three即:

    1. 拷贝构造
    2. 拷贝赋值
    3. 析构

    1. 编译器提供的默认函数

    声明一个空类

    声明一个空类,如下:

    class Empty {
    }
    

    C++会为上面定义的Empty类,提供默认的成员。效果等同于如下定义:

    class Empty {
    public:
    Empty() {...};
    ~Empty(){...};
    Empty(const Empty& rhs){...};
    Empty& operatpr = (const Empty& rhs) {...};
    }


    C++提供的默认函数

    • default 构造函数
    • copy构造函数
    • 析构函数
    • copy assignment函数

    原则 01: C++默认提供的函数仅在被调用时,编译器才会创建它们。
    注意:这四个函数都是public和inline的。


    默认函数的行为都是什么

    default构造和析构函数

    default 构造函数和析构函数主要是给编译器一个地方放置“藏身幕后”的代码。

    • default构造函数 :调用base classesnon-static 成员变量的构造函数。
    • 析构函数 :调用base classesnon-static 成员变量的析构函数。

    注意: non-static成员的说法,static 类成员不在default构造函数的初始化范围内。

    copy构造函数和copy assignment

    单纯的将对象的每一个non-static成员拷贝到目标对象。

    用户需要重新定义copy构造函数和copy assignment的场景

    类中包含以下类型成员

    • 引用类型
    • 指针类型
    • const类型

    2. 字符串设计

    1509260994792.png
    1. 用指针保存存储数据的地址,不用数组。好处在于灵活的存储,无需考虑设计多大的数组。

    实际是一种动态存储思想与静态存储思想之间的决策。

    3. ctor & dtor

    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] = '\0';
        }
    }
    
    inline string::~string() {
        delete[] m_data;
    }
    

    字符串的两种形式:

    1. 串+‘\0’
    2. 长度字段+串

    4. copy ctor & copy op =

    1509261365517.png

    浅拷贝 vs. 深拷贝

    在copy对象时仅copy指针成员属于浅copy, 创建新的内存并将指针的内容copy到新内存是深copy。

    在class with pointer 默认的copy ctor & copy op = 使用的是浅拷贝。

    浅拷贝造成的问题:

    浅拷贝会造成 alias(别名) 和 memory leak

    alias 与 野指针/悬空指针

    单一个内存单元被多个对象所只向时,可以看作是该内存单元存在了别名。

    // p_a 与p_b 构成了alias 
    int *p_a = new int();
    int *p_b = p_a;
    

    alias引入的问题:
    内存单元被释放时,其他地点的别名可能不知道该内存以被释放,继而继续使用该内存,产生不确定的行为(undefined behavior)

    1509262248771.png

    什么是悬空指针(dangling pointer)?

    If a pointer still references the original memory after it has been freed, it is called a dangling pointer.

    悬空指针是指针最初指向的内存已经被释放了的一种指针。

    什么是野指针(wild pointer)?

    A pointer in c which has not been initialized is known as wild pointer.

    野指针(wild pointer)就是没有被初始化过的指针.

    5. 拷贝赋值/copy assignment operator

    string& string::operator = (const string& str_r) {
        if (this == &str_r) {  // 自我检测
            return *this;
        }
    
        delete[] m_data;
        m_data = new char[strlen(str_r.m_data) + 1];
        strcpy(m_data, str_r.m_data);
    
        return *this;
    }
    

    注意⚠️:
    拷贝赋值中的自我检测

    copy op=的动作:

    1. 清空已有的数据
    2. 创建新内存
    3. 拷贝

    拷贝构造与拷贝赋值的差别

    1. 拷贝构造是创建新对象,拷贝已有对象到新对象
    2. 拷贝赋值时,两个对象都已经被创建。

    基于上述两点拷贝构造无需检测自我赋值,但拷贝赋值需要。


    内存管理

    1. stack vs. heap

    1509263493997.png

    stack, 是存在于某个作用域的一块内存空间。 例如函数被调用时,函数本身就会生成一个stack。

    heap,是指由操作系统提供的一块gloabl内存空间,可由程序员动态创建。

    2. static object & global object

    两者在生命周期都是在main结束之后,程序结束之后才结束。

    3. new: 先创建内存,后调用ctor

    1509262367694.png

    new的三个步骤

    // 原始语句
    complex* pc = new complex(1,2);
    // 编译器内部转换后的遇见
    void* mem = opreator new(sizeof(complex));  // 1. 分配内存
    pc = static_cast<complex*>(mem);  // 2. 类型转化
    pc->complex::complex(1,2);  // 3. 调用构造函数
    

    成员函数的调用过程

    哪个对象调用类成员函数,(编译器)默认将该对象的指针传给被调用成员函数this。

    pc->complex::complex(1,2);
    
    complex::complex(pc,1,2);
    

    3. delete:先调用dtor, 后释放内存

    1509262410676.png

    4. array new 一定要搭配 array delete

    1509262539128.png

    扩展补充:类模版..

    1. C++对象内存模型

    1. non-static 数据成员
    2. static 数据成员
    3. non-static 成员函数
    4. static 成员函数
    1509263831824.png
    1. static 数据成员/static成员函数/none -static成员函数 全局只有一份。
    2. none-static数据成员每个对象各有一份

    this指针

    哪个对象调用成员函数,哪个对象的指针就会作为参数传递给成员函数的this指针

    complex c1;
    c1.real();
    complex::real(&c1);
    
    1. none-static 成员函数通过this指针将处理不同对象的non-static数据。
    2. this pointer如何传递:non-static 成员函数是全局唯一的,哪个对象调用ns成员函数就将哪个对象的地址作为this指针传递给ns成员函数
    1509262669674.png

    static 成员

    static成员脱离于对象。成员函数也是脱离于对象。

    1. static 成员函数没有this pointer
    2. st 成员函数只能处理 st数据
    3. st成员函数没有this指针所以不能处理非st数据

    静态数据要在classbody外定义,定义时不要添加static声明。

    class acount{
        static int a;
    }
    
    int acount::a;  // 类st成员定义
    
    1. st 成员数据要在class body 外“定义”。这里是定义,因为要分配内存。
    2. static 成员函数的两种调用方式:object调用,classname 调用。

    设计static成员的原则

    如果数据是在对象间通用的,则将该数据设计为类的static成员。

    static 版本的singleton

    class singleton {
    public:
        static singleton& get_instance() {
            static singleton a;
            return a;
        }
    private:
        singleton() {};
        
    }
    

    cout

    1509263864546.png

    class template

    1509263880945.png

    function template

    1509263907947.png

    argument deduction (实参推导):

    1. argument deduction (实参推导):不同于class template , function template 在使用时不用指定具体类型

    名称空间

    相关文章

      网友评论

          本文标题:Boolan/C++面向对象高级编程 part2

          本文链接:https://www.haomeiwen.com/subject/yepypxtx.html