zoukankan      html  css  js  c++  java
  • C++面向对象高级开发课程(第二周)

    1. 类中含有指针—— class with pointer member(s) ——的情况经常发生,典型的有:string 类。

    2. STL中的 string 类太复杂,copy on write 等等特性。

    3. 采用“防卫式头文件声明”。

    4. s2 赋值给 s3。

    String s3("hello"), s2;
    s3 = s2;

    5. complier 会默认生成:拷贝构造函数 和 拷贝赋值函数(操作符重载),其执行的原理是按位依次赋值。指针的类不适合使用默认的构造函数。

    class String
    {
      public:
        String (const String& str); //拷贝构造函数
        String& operator= (const String& str); //拷贝赋值函数    
    }
    
    String s3(s1); //拷贝构造
    String s2 = s3; //拷贝赋值

    6. String 类实现原理

    class String
    {
      public:
        String(const char* cstr=0);
      private:
        char* m_data; //指针动态分配存储空间
    }
    
    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 = '';
       }
    }

    7. 只要类中带有指针,就必须自定义拷贝构造函数拷贝赋值函数

    8. 三个特殊函数(big three):拷贝构造、拷贝赋值、析构函数。

    9. 尽量使用“常量成员函数”:

    char* get_c_str() const
    {
        //do something  
    }

    10. 浅拷贝:编译器默认生成的类实例间拷贝行为,对带有指针的类来说会引发 memory leak。

          深拷贝:用户定义的行为(实质是一种构造函数)。

          兄弟——类的不同实例——间互为 friend(友元),可以直接取对方的私有成员。

    11. 一定要在 operator= 中检查是否 self assignment,是编程经验的体现。

    String& String::operator=(const String& str)
    {
       // check self assignment 
       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;
    }    

    12. stack and heap

    stack:

    存在于某scope(作用域)的一块内存空间(memory space)。例如当用户调用函数,函数本身会形成一个stack用来放置它所接收的参数,以及返回地址。

    在函数本体内声明的任何变量,其所使用的内存块都取自上述stack。

    heap:

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

    13. stack object 对象的生命期:

    class Complex {......};
    ......
    {
        Complex c1(2, 3);
    }

     c1便是 stack object,其生命在作用域(scope)结束之际结束。这种作用域之内的 object 又称为 auto object,因为它会被“自动”清理。

    14. static local object 对象的生命期:

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

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

    15. global object 对象的生命期:

    class Complex {......};
    ......
    Complex c1(2, 3);
    
    int main()
    {
        //do sometihing
        return 0;        
    }

     c1便是所谓 global object,其生命期在整个程序结束之后才结束,也可以视为一种 static object,作用域是“整个程序”。

    16. (对象的) 存在/消失 ≈ 构造/析构 (函数)何时被调用。

    17. heap objects 对象的生命期:

    class Complex {......};
    ...
    {
        Complex *p = new Complex;
        ...
        delete p;
    }

      p 所指的是 heap objects ,其生命在它被 delete 之际结束。

     若当作用域结束还未 delete 则会内存泄漏(memory leak):因为当作用域结束时,指针p所指的heap object仍然存在,但指针p的生命却结束了,作用域之外再也看不到指针p,也就没机会 delete p。

    18. new: 先分配memory,再调用constructor

    Complex *p = new Complex(1, 2);

     以上的一行代码,编译器会转化为:

    Complex *pc;
    
    void* mem = operator new( sizeof( Complex ) ); // 分配内存
    pc = static_cast<Complex*>(mem);               // 转型
    pc->Complex::Complex(1, 2);                    // 构造函数
    • operator new——操作符“new”——是C++函数,其内部调用malloc()。
    • pc->Complex::Complex(1, 2); => Complex::Complex(pc, 1, 2); / Complex::Complex(this, 1, 2);

    19. delete:先调用 de-constructor,在释放内存

    Complex *ps = new String("hello world");
    ...
    delete ps;

    编译器转化为

    Complex::~Complex(ps); // 析构函数
    operator delete(ps);   // 释放内存
    • operator delete(ps); 内部调用 free(ps)

    20. array new 一定要搭配 array delete。

    String *p = new String[3];
    ...
    delete[] p;

    21. 头文件.h 防卫式声明

    22. 32位平台下,一根指针 4 字节。

    23. return by reference 使用门槛:传递的 object 不是 local object。

    24. “常量成员函数”:不修改类成员数据部分的函数。

    char* get_c_str() const
    {
        // do something  
    }

    const 加在 ()与{}之间。

    25. inline 关键字一定要加!全部的,无负面作用。

    26. static data member 内存中只有一份,不在乎存在多少实例。

         static data memeber 一定在类的声明之外设初值。

         static member function 调用方式有二:(1)通过 object 调用(2)通过 class name 调用。

    class Account {
        static void set_rate(double val);
    };
    
    Account::set_rate(8.0); // 通过类名调用
    
    Account a1;
    a1.set_rate(8.0); // 通过实例调用

    27. Q:“声明”和“定义”的区别? 

         A:定义会程序获得内存。

    28. singleton——把ctor放在private区

    class A{
    public :
        static A& getInstance(){ return a; }
        setup();
    private:
        A();
        A(const A& ths);
        static A a;
    };
    // 调用示例
    A::getInstance().setup();

    29. Meyer`s singleton——把ctor放在private区

    把静态的“自己”放在函数里。好处:只有当函数被调用时,才创建object,即使离开函数以后static object也依然存在。如果该函数没被调用过,那么连一个static object也不会存在。

    class A{
    public :
        static A& getInstance();
        setup();
    private:
        A();
        A(const A& ths);
        static A a;
    };
    
    A& A::getInstance()
    {
        static A a;
        return a;
    }
    // 调用示例
    A::getInstance().setup(); 

     30. Q:为什么cout可以接收各种内置类型“对象”?

          A:因为标准库对“<<”做了针对各种内置类型的运算符重载

    31. “template会造成代码膨胀是必要的”——侯捷

         代码膨胀:模版会针对用户定义的每一种类型都生成一份代码,代码的大意相同,只是类型不同。

    32. class template

    template <typename T>
    class Complex {
    public:
        Complex(T r = 0, T i = 0)
            : re(r), im(i)
        {}
    private:
        T re, im;
    };
    
    int main()
    {
        complex<double> c1(1, 2);
        return 0;
    }

     33. function template

    class Complex {
    public:
        bool operator< (const Complex& ths) const
        {...}
    };
    
    template <class T>
    inline const T& min(const T& a, const T& b)
    {
        return b < a ? b : a; //  编译器遇到“<”会自动寻找对应类型的运算符重载
    }
    
    int main()
    {
        Complex c1, c2, c3;
        c3 = min(c1, c2);
    }

     对于 c3 = min(c1, c2) 不必明确指出类型,因为complier会对function template进行实参推导(argument deduction)。

    34. namespace

    using directive

    using namespace std;

    using declaration

    using std::cout
    
    std::cin >> ...
    cout << ...

    35. string.h 代码:

    #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 = '';
       }
    }
    
    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

    36. 更多细节深入

    •operator type() const;
    •explicit complex(…) : initialization list { }
    •pointer-like object
    •function-like object
    •Namespace
    •template specialization
    •Standard Library
    •variadic template (since C++11)
    •move ctor (since C++11)
    •Rvalue reference (since C++11)
    •auto (since C++11)
    •lambda (since C++11)
    •range-base for loop (since C++11)
    •unordered containers (Since C++)

  • 相关阅读:
    2018-8-10-win10-uwp-win2d-使用-Path-绘制界面
    2018-8-10-win10-uwp-win2d-使用-Path-绘制界面
    PHP money_format() 函数
    PHP metaphone() 函数
    PHP md5_file() 函数
    PHP md5() 函数
    PHP ltrim() 函数
    查看统计信息
    CF960F Pathwalks_权值线段树_LIS
    hdu 5691 Sitting in line 状压动归
  • 原文地址:https://www.cnblogs.com/fengyubo/p/4795669.html
Copyright © 2011-2022 走看看