美文网首页
侯捷 视频 上

侯捷 视频 上

作者: my_passion | 来源:发表于2020-06-08 23:13 被阅读0次

1 C++简介

OOP: Object Oriented Programming 
    面向对象: 是一种思想

procedural language: 过程式语言

1.1 class 设计

小代码 & 良好的 c++ 编程习惯

1   Object Based

    基于对象: 单一 class 

        2种 经典 class 分类:
            class with / without pointer members: String / Complex

2   Object Oriented

    面向对象: 多个class, 主要考虑 class 间关系

        继承  inheritance
        组合  composition
        委托  delegation

1.2 C++ 演化

    new C -> C with class -> C++: 1983

    C++98(1.0) -> C++11(2.0)

1.3 相比于 C, C++ 更注重 标准库

    C: 主要关注 语言层面

    C++: C++ 语言 &  C++ 标准库

1.4 好书

    1   语言部分

        全世界最畅销的2本

            << C++ Primer >> C++ 第1个编译器作者

            << The C++ Programming Language >> C++之父 Bjarne Stroustrup

    2   专家经验

        << Effective C++>>

    3   标准库

        << The C++ Standard Liarbry >>

        << STL 源码剖析 >>

        STL: Standard Template Library, 是 标准库的前身 

2 class 声明

2.1 C++ 与 C: ptr 和 func 不同

    C:
        数据: 具有 类型/type (build-in, struct)
            据 类型 create 出 Variables

        函数: 处理 variables

    C++:
        wrap ptr 和 ( 处理 ptr 的 ) func, 形成 class

        以 class 为 type create 出 objects

        C++ 的 class 源于 C 的 struct, 又加入了新特性
        
        ptr/对象 可能有 多份/多个, 处理对象的 `函数 只有1份`

2.2 C++ ptr 与 func

    1   Complex

        ptr:      实部 虚部
        
        Functions:  

            

    2   String
    
        ptr: ptr — 指向1个 字符串

        functions: copy 等

2.3 C++ 代码

    .h/hpp: 标准库
    .h    : class Declaration
    .cpp: include<> + include " "

2.4 C++ / C: 输出

C++: 不需要 告诉编译器 要输出的变量 类型

    //c++
    int i = 5;
    cout << i << endl;

    //c
    printf("%d\n", i);

2.5 头文件 & 防卫式声明

程序 中 第1次 include 头文件 时, 
    由于 未曾定义过  _COMPLEX_  这个 name, 所以定义它; 
    然后进入 头文件 body. 

第2次 include 头文件 时, 
    由于 已定义过 _COMPLEX_ , 所以 不会进入 头文件 body

// complex.h
#ifndef _COMPLEX_
#define _COMPLEX_
...
#endif

2.6 头文件布局

    // A.h
    #ifndef _A_
    #define _A_

    // (1) 前置声明
    class B;

    // (2) class 声明
    class A
    {
        // class body 内  直接定义 的 函数
    };

    // (3) class body 外 定义 的 函数
    A::function ...

    #endif

3 构造函数

1   class 声明

    class complex
    {         // class body
        friend complex& _doapl (complex*, const complex&);
    public:
        complex (double r = 0, double i = 0) // 1. default arg
            : re (r), im (i)  // 2. initialization list 初始化列表, 只有 ctor 享有这种语法
        { }

        complex& operator+=(const complex&); 
        
        double real () const { return re; }
        double imag () const { return im; }
    private:
        double re, im;
    };

2   inline func

    inline 好处: 非函数调用

    函数 `建议` 编译器 把自己做成 inline(候选人) 的 2种情形:

    (1) class body 内 定义 => `自动成为 inline 候选人`

    (2) class body 外 explicitly 声明为 inline

3   ctor

    可 overload

        (1) 在 编译器 看来, 重载函数 不同名

        (2) 二义性 -> 编译器 不知道 调哪个 -> 编译 error

            complex (double r = 0, double i = 0) 
                : re (r), im (i) { }
                
            complex () : re(0), im(0) {}; 

4 参数传递 与 返回值

1 ctor 放 private => class 称为 Singleton 单例

(1) class 只在 内部 构造 1份 自己的 static obj, 供 外部 使用

(2) 不允许外界 创建 object

    class A
    {
    public:
        static A& getInstance();
        setup(){ /* */ }
    private:
        A();
        A(const A& rhs);
    };

    A& A::getInstance()
    {
        static A a;
        return a;
    }

    // 调用 A::getInstance().setup();

2 const member func: 不改 mem ptr

const obj 调 non-const mem func => compiler 报错

    `const 对象: 告诉 编译器, 不能改 mem ptr`
    `non-const mem func: 允许改 mem ptr`

    class 
    {    
    public:
        double complex::real () const { return re; }
    };

3 参数传递: pass by value vs. pass by reference (to const)

能传引用 就 传引用

(1) 引用
    [1] 本质上 也是 指针, 传引用 像 传指针 一样快

    [2] 必须 绑定到 已有对象

(2) 指针: 可以是 动态内存的地址 => 此时 必须用指针, 不能用引用

(3) 何时 不 pass by reference:

1) iterator

    : cheap-to-copy, pass by value 比 by const reference 更高 效
        reference 本质是 指针
        而 iterator 不过是指针的一种抽象

2) local obj

(4) 编译器 如何看待 操作符?

`二元操作符:` 
    编译器 把 操作符 作用在 左边
    若 左边 重载了该操作符
        把 操作符 编译成 调用 相应的 重载函数
    ostream&
    operator << (ostream& os, const complex& x)
    {
        return os << '(' << real(x) << ',' << imag(x) << ')';
    }

    // 编译器 找 << 的 matched 重载版本: 
    // 对 non-memFunc 而言, << 左操作数 cout 匹配 operator << () 的 para1: ostream& os
    cout << c(2, 1) << endl;

4 返回值传递: return by value / return by reference (to const)

能传引用 就 传引用

5 友元 / friend

(1) 直接访问 friend 的 private 成员: 通过 pointer / reference / obj => 打破封装

(2) note: 同一 class 各 objects 互为友元

    // (1)
    inline complex&
    _doapl (complex* ths, const complex& c)
    {
        ths->re += c.re;  
        ths->im += c.im;
        return *ths;
    }
    
    // (2) 同一 class 各 objects 互为友元 ( c.re )
    class complex
    {
    public:
        ...
        int fun(const complex& c)
        {
            return c.re + c.im;
        }
        ...
    };

    {
        complex c1(2, 1);
        complex c2;
        
        c2.fun(c1);
    }

6 class body 外 定义

    class body 之外 的 函数: 
        用 类名限定 的是 mem func; 否则是 global func

    inline complex&
    _doapl (complex* ths, const complex& c) 
    {   //第 1/2 参数 会/不会 被改变
        ths->re += c.re;  
        ths->im += c.im;
        return *ths;
    }

    inline complex&
    complex::operator += (const complex& c)
    {
        return _doapl(this, c);
    }

5 操作符重载

1 mem func with this (implicit para: point to the obj calling the mem func)

func 中 某段 处理 提取成单独的函数, 以 实现 复用

    complex c1(2, 1);
    complex c2(5);

    c2 += c1; 

    inline complex&
    complex :: operator += (const complex& c)
    {
        //2. 右边 加到 左边 的这种动作 是一个通用动作,可以单独成函数,供其他 函数调用
        return _doapl(this, c);
    }

    inline complex&
    _doapl (complex* ths, const complex& c) //第1参数 会被改变,第2参数不会被改变
    {
        ths->re += c.re;  
        ths->im += c.im;
        return *ths;
    }

2 non-mem func without this

    对某个 操作符重载, 
    只能 写为 `mem func 或 non-mem func` 之一, 
    但两者 `不能同时存在`
// 支持  c1 += c2;
inline complex
operator += (const complex& x, const complex& y)
{
    return complex( real(x) + real(y), imag(x) + imag(y) );
}

// 支持  c1 += 5;
inline complex
operator += (const complex& x, double y)
{
    return complex( real(x) + y, imag(x) );
}

3 temp object

不能 return by reference: 生命到下一行语句就结束了

    inline complex
    operator += (const complex& x, const complex& y)
    {
        return complex( real(x) + real(y), 
                        imag(x) + imag(y) );
    }

4 return by reference

发端 无需知道 收端 是以 什么形式 接收: 收端 以 value / reference 接收, 发端 都是同一形式 发送

vs. return by pointer: 发端 必须知道 传的是 pointer => 以 pointer 收, 必须以 pointer 发

    // Note: 返回引用:以 [1] 支持 c3 += c2 += c1 [2] 加完之后更新 左值
    inline complex&
    _doapl (complex* ths, const complex& c)
    {
        ...
        return *ths;
    }

    complex::operator += (const complex& c)
    {
        return _doapl(this, c);
    }

6 复习 Complex 类 的实现

// 1    防卫式 声明 
#ifndef _COMPLEX_
#define _COMPLEX_

#endif

// 2    class name
class complex
{

};

// 3    mem ptr
class complex
{
private:
    double re, im;
};

// 4    ctor
class complex
{
public:
    complex (double r = 0, double i = 0)
        : re (r), im (i) {  }
private:
    double re, im;
};

// 5    interface func
// 不改变 mem ptr 的 mem func: 写为 const mem func
// friend func:
class complex
{
    friend complex& _doapl (complex*, const complex&);
public:
    complex (double r = 0, double i = 0)
        : re (r), im (i) { }

    complex& operator += (const complex& );
    double real () const { return re; }
    double imag () const { return im; }

private:
    double re, im;
};

6 class body 外 operator+= 定义

1) 设计 func 的 interface

    [1] func name
    
        complex::operator+=

    [2] para
    
        1> mem func => 只需要 右边
        2> 先考虑 传 reference
        3> 右边加到左边, 右边不动 => const 引用
            complex::operator+=(const complex& c)

    [3] return type
    
        1> 得 左边这种 type
        
        2> `return` 的 不是 函数内部创建的 local/temp obj,
            而是 `已经存在的对象 (如 left operand obj)` 时, 
            => 可以传 reference

        complex&
        complex::operator+=(const complex& c)

    [4] 函数 body 之外 => 建议 为 inline

        inline complex&
        complex::operator+=(const complex& c)

2) 设计 func 的 definition

    [1] 右边 加到 左边 是 通用动作,
        可   抽取出 作 commonFunc

    Note: 把 本 func 要做的事情 丢给 另一 func,
        本 func 与 另一 func: 
            1] return type 相同, 
            2] 相同参数部分 type 相同

    [2] 把 this 当 arg 传给 `commonFunc`

        inline complex&
        complex::operator+=(const complex& c)
        {

            return _doapl(this, c);
        }

    [3] 第1参数 会被改变,第2参数 不会被改变(=> const)

        inline complex&
        _doapl (complex* ths, const complex& c) 
        {
            ths->re += c.re;  
            ths->im += c.im;
            return *ths;
        }
7   加

    加 可以 是 复数 加 复数, 复数 加 实数 等, 
        
        => 写成 non-mem func 更好

8   输出

    cout << c1; 

    (1) 往 os 里 写时, os 状态 改变 
        => os non-const reference

    (2) 输出的 对象 状态不变 => const reference

    (3) 对象 cout/os 类型为 ostream

    operator << (ostream& os, 
                  const complex& x)

    (4)为 支持 cout << obj1 << endl; 
        => cout << obj1 应 return cout 的类型 ostream

    (5) cout 不是函数的 local 对象, 而是 本来就有的  
        
        => 可以 return reference

        ostream&
        operator << (ostream& os, const complex& x)
        {

        }

    (6) 按用户想要的方式输出

    ostream&
    operator << (ostream& os, const complex& x)
    {
        return os << '(' << real(x) << ',' << imag(x) << ')';
    }

7 带 pointer 的类 — copy control: copy ctor / copy assignment / dtor

(1) class 带 pointer men, 多半是要 `动态内存分配`
    => 对象 生命结束前, dtor 被调用, 
        必须在 dtor 中 释放 动态分配的内存

(2) class with pointer members 必须有 copy ctor 和 copy op=

(3) 若无 自我赋值, 则
左 / 右 pointer ( this->ptr / rhs.ptr) 指向 同一块内存,
delete[] 左 ponter 后, 该 内存释放,
再 strcpy(this->ptr, rhs.ptr) 会产生 undefined behavior

(4) 让 字符串 里 拥有 一个 poiner, 需要 内存时, 才去创建 另一空间 来放 字符串本身

    因为 字符串 内容 有大有小, 这种设计 最好, 
    而不是在 字符串里 放一个 array

    String s1();  // ctor,未 指定初值 
    String s2("hello"); // ctor

    String s3(s1);  // copy ctor
    cout << s3 << endl;

    s3 = s2; // copy assignment
    cout << s3 << endl;
    class Stirng
    {
    private:
        char* ptr;
    public:
        String(const char* cstr = 0); // ctor

        // copy ctor/assignment: 接收的是 自己这种东西 
        // => para 为 const String&
        String(const String& str);    
        String& operator = (const String& str);
        ~String();

        char* get_c_str() const { return ptr; }
    };

    // copy ctor 
    inline
    String::String(const char* cstr = 0)
    {
        if(cstr)
        {
            ptr = new char[strlen(cstr) + 1];
            strcpy(ptr, cstr);
        }
        else  // 未 指定初值  eg: String s1();
        {
            ptr = new char[1];
            *ptr = '\0';
        }
    }

    inline
    String:: ~String()
    {
        delete[] ptr;
    }

    // operator =
    inline 
    String& String::operator = (const String& str)
    {
        if(&str == this) // 检测自我赋值
            return *this;
        
        delete[] ptr;
        ptr = new char[ strlen(str.ptr) + 1];
        strcpy(ptr, str.ptr);
        
        return *this;
    }
1.jpg

8 堆 栈 内存管理

8.1 object 生命期

    1   栈 Stack

        `某 scope 内`  memory space

    2   堆 Heap

        `OS 提供 global memory space`

            通常以 new/delete 分配/释放


        `内存泄漏 : 只 分配 不 释放`

            ptr 离开 scope 之后就消亡了, 但 ptr 所指 memory 还在`

    3   stack object

        `dtor 会 自动被调用 => 会被 自动 清理`

        scope   : 其所在的 scope
        lifetime: 其所在的 scope
    
    4   static local objects

        scope   : 其所在的 scope
        lifetime: 持续到 整个程序结束 

        {
            static Complex c2(1, 2);
        }

    5   global objects

        scope   : 持续到 整个程序结束 
        lifetime: 持续到 整个程序结束 

    6 heap objects
    
        scope   : 
        lifetime: 被 delete 时结束

8.2 new / delete / new [] / delete []

9 String 类 实现过程

(1) copy ctor

    蓝本 是 自身 type 的 obj, 改变了 目的端 ptr 
        => 不能是 const func

(2) copy assignment
    1) 目的端 本来就存在 => return reference
    2) 改变了 目的端 ptr => 不能是 const func

(3) C风格字符串
    return pointer to 字符串

    char* get_c_str() const { return ptr; } 

第10讲 class/function template

第11讲 虚函数 与 多态

https://www.jianshu.com/p/eb69e02766e7

第12讲 组合 与 继承

https://www.jianshu.com/p/0f209eb83f47

第13将 委托

https://www.jianshu.com/p/0f209eb83f47

1. Comopsite - 设计模式

2. Prototype - 设计模式

相关文章

网友评论

      本文标题:侯捷 视频 上

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