C++ 基础 候捷老师(下)笔记

C++ 侯捷老师基础视频补充


01 convesion function,转换函数

  • 转换函数只能转换为任意 type 只要前面出现过
  • 不需要写返回类型
class Fraction 
{
public:
    Fraction(int num, int den = 1)
        : m_numerator(num), m_denominator(den) { }
    operator double() const 
    {
        return (double)m_numerator / m_denominator;         
    }

private:
    int m_numerator;     // 分子
    int m_denominator;   // 分母
}

int main(void)
{
    Fraction f(3, 5);
    double d = 4 + f;

    std::cout << "d = " << d << std::endl;
}

02 non-expicilt-one-argument ctor

  • 编译器可以在适合的时候将别的类型转换为该 类的类型
  • 构造函数不加 explicit 就是可以转换
  • 构造函数加 explicit 就是不可以加
  • 需要具体问题具体分析,到底是不是正确
class Fraction 
{
public:
    Fraction(int num, int den = 1)
        : m_numerator(num), m_denominator(den) { }
    // operator double() const 
    // {
    //     return (double)m_numerator / m_denominator;
    // }
    
    Fraction operator+(const Fraction& f)
    {
        return Fraction(this->m_n() + f.m_n(), 
                this->m_d() + f.m_d());
    }

    void print()
    {
        std::cout << "分子 = " << m_numerator << std::endl;
        std::cout << "分母 = " << m_denominator << std::endl;
    }

    int m_n() const 
    {
        return m_numerator;
    }
    int m_d() const 
    {
        return m_denominator;
    }

private:
    int m_numerator;     // 分子
    int m_denominator;   // 分母
};

int main(void)
{
    Fraction f(3, 5);

    Fraction fr = f + 4;
    fr.print();

    return 0;
}

03 pointer-like classes,关于智能指针

  • * 操作符重载
  • -> 操作符重载
template<class T>
class shared_ptr
{
public:
    T& operator*() const
    { return *px; }
    
    T* operator->() const
    { return px; }

    shared_ptr(T* p)
        : px(p) { }

private:
    T* px;
    long* pn;
}


struct Foo
{
    void methon(void)
    {
        std::cout << "TEST" << std::end; 
    }
}

int main(void)
{
    shared_ptr<Foo> sp(new Foo());

    (*sp).methon();
    sp->methon();

    return 0;
}

04 pointer-like classes,关于迭代器

  • ++ 操作符重载
  • – 操作符重载
  • == 操作符重载
  • != 操作符重载
  • * 操作符重载
  • -> 操作符重载

05 function-like classes,仿函数

  • () 操作符重载
  • 类中有 () 符号重载
  • 标准库中,仿函数会继承

06 member template 成员模板

  • 让构造函数更有弹性
  • 继承的类赋予给父类
Basel* ptr = new Derviedl;  // up-cast

shared_ptr<Basel>sptr(new Derivedl); // 模拟 up-cast

template<typename T>
class A
{
public:
    A(T n)
     : num(n) { }
    void print()
    {
        std::cout << "num = " << num << std::endl;
    }

    T num;
};

template<typename TT>
class B:public A<TT>
{
public:
    template<typename TTT>
    explicit B(TTT n)
        : A<TT>(n) { }
    
};


int main(void)
{
    // 输出 3
    A<int> a(3);
    a.print();

    // 警告 输出 3
    A<int> aa(3);
    aa.print();

    // 不会警告,输出 3
    B<int>b(3.2);
    b.print();

    // 输出 3.2
    B<float>c(3.2);
    c.print();

    return 0;
}

07 specialization,模板特化

template<typename T>
class A
{
public:
    A(T n)
     : num(n) { }
    void print()
    {
        std::cout << "num = " << num << std::endl;
    }

private:
    T num;
};

template<>
class A<int>
{
public:
    A(int n)
     : num(n) { }
    void print()
    {
        std::cout << "这是整个模板特化的 int 函数" << std::endl;
        std::cout << "num = " << num << std::endl;
    }
private:
    int num;
};

int main(void)
{
    A<int> a(3);
    a.print();

    A<float> b(3.2);
    b.print();
    
    return 0;
}

08 partial specialization,模板偏特化

  • 个数上的偏
  • 范围的偏
template<typename T, typename U>
class A
{
public:
    A(T n, U d)
     : num(n), data(d) { }
    void print()
    {
        std::cout << "num = " << num << std::endl;
        std::cout << "data = " << data << std::endl;
        std::cout << std::endl;
    }

private:
    T num;
    U data;
};

template<typename U>
class A<int, U>
{
public:
    A(int n, U d)
     : num(n), data(d) { }
    void print()
    {
        std::cout << "这是模板偏特化的 pint 函数" << std::endl;
        std::cout << "num = " << num << std::endl;
        std::cout << "data = " << data << std::endl;
        std::cout << std::endl;
    }
private:
    int num;
    U data;
};

int main(void)
{
    // 输出结果 3 3
    A<int, int> a(3, 3);
    a.print();

    // 输出结果 3.2 3
    A<float, int> b(3.2, 3);
    b.print();
    
    return 0;
}

template<typename T>
class A
{
public:
    A(T n)
     : num(n) { }
    void print()
    {
        std::cout << "num = " << num << std::endl;
        std::cout << std::endl;
    }

private:
    T num;
};

template<typename T>
class A<T*>
{
public:
    A(T* pn)
     : num(pn) { }
    void print()
    {
        std::cout << "这是整个模板偏特化的 pint 函数" << std::endl;
        std::cout << "num = " << num << std::endl;
        std::cout << "*num = " << *num << std::endl;
    }
private:
    T* num;
};

int main(void)
{
    // 输出结果 3.2
    A<float> b(3.2);
    b.print();
    
    // 输出结果 内存地址 + 3.2
    float f = 3.2;
    A<float*> c(&f);
    c.print();

    return 0;
}

09 template template parameter,模板模板参数

template<typename T>
class A
{
public:
    A(T n)
     : num(n) { }
    void print()
    {
        std::cout << "num = " << num << std::endl;
        std::cout << std::endl;
    }

private:
    T num;
};

template<typename T,
        template <typename U> 
            class C
        >
class B
{
public:
    B(T n)
     : num(n) { }
    void print()
    {
        std::cout << "这是 模板模板参数 的 print 函数" << std::endl;
        std::cout << "num = " << num << std::endl;
        a.print();
    }
private:
    T num;
    // C<T> a(3.2);  // 为什么这样的方式会报错
    // 为什么 这样的方式就可以
    C<T> a = C<T>(3.2);
};

int main(void)
{
    // 编译会有警告,以为 上面 4 行是 浮点数,这里是整数类型
    // 输出结果  3 3
    B<int, A> b(3);
    b.print();
    
    // 输出结果 3.2 3.2
    B<float, A> c(3.2);
    c.print();

    return 0;
}

10 关于 C++ 标准库

  • Iterators 迭代器
  • Contaliners 容器
  • Functors 仿函数
  • Algorithms 算法

  • Sequence containers
    • array
    • verctor
    • deque
    • forward_list
    • list
  • Container adaptor
    • stack
    • queue
    • priority_queue
  • Associative containers
    • set
    • multiset
    • map
    • multimap
  • Unordered associative con
    • unordered_set
    • unordered_multiset
    • unordered_map
    • unordered_multimap
  • Sorting
    • sort
    • stable_sort
    • partial_sort
    • partial-sort——copyis-sorted
    • is_sorted_until
    • nth_element
  • Binary search
    • lower_bound
    • upper_bound
    • equal_range
    • binary_search
  • Merge
    • merge
    • inplace_merge
    • includes
    • set_union
    • set_intersection
    • set_difference
    • set_symmetric_difference

注意:自己能将这些数据结构,函数,算法使用一次效果最好


11 variadic templates (since C++ 11)

  • 想知道后面的参数有多少个 sizeof...(args)
  • 在函数和类中都可以使用
  • ... 就是一个所谓的 pack(包)
  • 用于 template parameters,就是 template parameters pack(模板参数包)
  • 用于 function parameter types,就是 function parameter types pack(函数参数类型包)
  • 用于 function parameters,就是 functionparameters pack(函数参数包)
#include <iostream>
#include <bitset>

void print()
{
}
           
template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args)
{
    std::cout << firstArg << std::endl;
    print(args...);
}
 
int main(void)
{
    print(7.5, "hello", std::bitset<16>(377), 42);

    return 0;
}

12 auto (since C++11)

#include <iostream>
#include <list>
#include <string>
           
using namespace std;
 
int main(void)
{
    list<string> c;
    c.push_back("no one on");
    c.push_back("This is str one.");
    c.push_back("test tes three");
    c.push_back("the end one");

    c.sort();

    // list<string>::iterator ite;
    // for (ite = c.begin(); ite != c.end(); ite++)
    for (auto ite = c.begin(); ite != c.end(); ite++)
    {
        cout << *ite << endl;
    }

    return 0;
}

13 ranged-base for (since C++11)

#include <iostream>
#include <list>
#include <string>
           
using namespace std;
 
int main(void)
{
    list<string> c;
    c.push_back("no one on");
    c.push_back("This is str one.");
    c.push_back("test tes three");
    c.push_back("the end one");

    c.sort();

    for (auto& ite : c)
    {
        cout << ite << endl;
        ite = "test";
    }

    cout << endl; 
    for (auto ite : c)
    {
        cout << ite << endl;
    }

    cout << endl; 
    for (auto i : {1, 2, 3, 4, 5})
    {
        cout << i << endl; 
    }

    return 0;
}

14 reference

  • object 和 reference 的大小相同,地址也相同
  • 常见用途
  • 多半用在传输传递上
  • 以下被认为 same signature 所以不能同时存在
double imag(const double& im) { ... }
double imag(const double  im) { ... }   // Ambiguity

#include <iostream>
           
using namespace std;
 
int main(void)
{
    int x = 0;
    int *p = &x;
    int& r = x;
    int x2 = 5;

    cout << "x = " << x << endl;
    cout << "p = " << p << endl;
    cout << "*p = " << *p << endl;
    cout << "r = " << r << endl;
    cout << "x2 = " << x2 << endl;

    cout << endl;
    r = x2;         // r 不能重新代表其他东西,现在 r x2 都是 5 了
    cout << "r = " << r << endl;
    cout << "x = " << x << endl;
    cout << "x2 = " << x2 << endl;

    return 0;
}

#include <iostream>
           
using namespace std;

typedef struct Stag
{
    int a;
    int b;
    int c;
    int d;
} S;
 
int main(void)
{
    double x = 0;
    double* p = &x;  // p 指向 x, p 的值是 x 的地址
    double& r = x;   // r 代表 x,现在 r x 都是 0

    // 64 位系统下测试
    cout << sizeof(x) << endl;   // 8
    cout << sizeof(p) << endl;   // 8
    cout << sizeof(r) << endl;   // 8
    cout << p << endl;           // 0x7ffe355f1920
    cout << *p << endl;          // 0
    cout << x << endl;           // 0
    cout << r << endl;           // 0
    cout << &x << endl;          // 0x7ffe355f1920
    cout << &r << endl;          // 0x7ffe355f1920
    cout << endl;

    S s;
    S& rs = s;
    cout << sizeof(s) << endl;   // 16
    cout << sizeof(rs) << endl;  // 16
    cout << &s << endl;          // 0x7ffe355f1900
    cout << &rs << endl;         // 0x7ffe355f1900

    return 0;
}

15 对象模型 (Object Model) : 关于 vptr 和 vtbl

  • 多态 动态绑定 虚函数 是一回事
  • 第一 通过指针调用
  • 第二 向上转型
  • 第三 调用虚函数
  • 编译器编译为动态绑定


#include <iostream>
#include <list>
           
using namespace std;

class A 
{
public:
    virtual void print(void)
    {
        cout << "Test this is A virtual print." << endl;
    }
};

class B: public A
{
public:
    virtual void print(void)
    {
        cout << "Test this is B virtual print." << endl;
    }
};

class C: public A
{
public:
    virtual void print(void)
    {
        cout << "Test this is C virtual print." << endl;
    }
};
 
class D: public B
{
public:
    virtual void print(void)
    {
        cout << "Test this is D virtual print." << endl;
    }
};


int main(void)
{
    list<A*> lt;
    A* a = new A();
    B* b = new B();
    C* c = new C();
    D* d = new D();

    lt.push_back(a);
    lt.push_back(b);
    lt.push_back(c);
    lt.push_back(d);

    for (auto ite = lt.begin(); ite != lt.end(); ite++)
    {
        // 多态 动态绑定 虚函数
        (*ite)->print();
        (*(*ite)).print();
    }
        
    delete a;
    delete b;
    delete c;
    delete d;

    return 0;
}

16 Object Model : 关于 this

  • 通过一个对象调用一个函数,那个对象的地址就是 this


17 Object Model : 关于 Dynamic Binding

#include <iostream>
           
using namespace std;

class A 
{
public:
    virtual void print(void)
    {
        cout << "Test this is A virtual print." << endl;
    }
};

class B: public A
{
public:
    virtual void print(void)
    {
        cout << "Test this is B virtual print." << endl;
    }
};

int main(void)
{

    B b = B();
    A a = (A)b;

    b.print();      // B
    a.print();      // A   因为 a 是一个对象
    (&a)->print();  // A   因为 a 是一个对象

    A* pa = &b;
        
    pa->print();    // B   因为 pa 是一个指针
    (*pa).print();  // B   因为 pa 是一个指针

    pa = new B();
    pa->print();    // B
    (*pa).print();  // B

    delete pa;

    return 0;
}

18 重载 new / delete

  • 重载全局的 ::operator new, ::operator delete, ::operator new[], ::operator delete[]
#include <iostream>
           
using namespace std;

void* operator new(size_t size)
{
    cout << "Test void* operator new(size_t size) \n";
    return malloc(size);
}

void* operator new[](size_t size)
{
    cout << "Test void* operator new[](size_t size) \n";
    return malloc(size);
}

void operator delete(void* ptr)
{
    cout << "Test void operator delete(void* ptr) \n";
    free(ptr);
}

void operator delete[](void* ptr)
{
    cout << "Test void operator delete[](void* ptr) \n";
    free(ptr);
}

int main(void)
{
    int* pi = new int();
    delete pi;
    cout << endl;

    int* pj = new int[3];
    delete[] pj;
    cout << endl;

    int* pn = ::new int();
    ::delete pn;

    return 0;
}

  • 重载 member operator new / delete, new[] / delete[]
  • 当成员 new delete 重载时可以通过 ::new ::delete 来调用全局的 new / delete
#include <iostream>
#include <string>
           
using namespace std;

class Foo
{
public:
    int id;
    long data;
    string str;

    Foo()
     : id(0) 
    {
        cout << "default ctor this = " << this << " id = " << id << endl;
    }
    Foo(int i)
     : id(i) 
    { 
        cout << "ctor.this = " << this << " id = " << id << endl;
    }

    ~Foo()
    {
        cout << "dtor.this = " << this << " id = " << id << endl;
    }

    virtual void print() { }

    static void* operator new(size_t size);
    // static void operator delete(void* pdead);
    static void operator delete(void* pdead, size_t size);
    static void* operator new[](size_t size);
    // static void operator delete[](void* pdead);
    static void operator delete[](void* pdead, size_t size);
};

void* Foo::operator new(size_t size)
{
    Foo* p = (Foo*)malloc(size);
    cout << "new size = " << size << endl;
    return p;
}

void* Foo::operator new[](size_t size)
{
    Foo* p = (Foo*)malloc(size);
    cout << "new[] size = " << size << endl;
    return p;
}

void Foo::operator delete(void* pdead, size_t size)
{
    cout << "delete size = " << size << endl;
    free(pdead);
}

void Foo::operator delete[](void* pdead, size_t size)
{
    cout << "delete[] size = " << size << endl;
    free(pdead);
}

int main(void)
{
    Foo* pf = new Foo(7);
    delete pf;

    cout << endl;
    Foo* pff = new Foo[5];
    delete[] pff;

    cout << endl;
    Foo* pfn = ::new Foo(2);
    ::delete pfn;

    return 0;
}

  • 重载 palcement arguments new() delete()
  • 第一个参数的 type 必须是 size_t
  • 第一个参数默认传的就是穿件对象的 size 大小
  • 可以写多个参数的 new()
  • 也可写相对应的多个参数的 delete()
  • 也可以不写,只有当 new() 所调用的构造函数发生异常的时候,才会调用相应的 delete()
  • 重载 new() delete() 用来自己想多分配一些东西
#include <iostream>
#include <string>
           
using namespace std;

class Bad
{};

class Foo
{
public:
    int id;
    long data;
    string str;

    Foo()
     : id(0) 
    {
        cout << "default ctor this = " << this << " id = " << id << endl;
    }
    Foo(int i)
     : id(i) 
    { 
        cout << "ctor.this = " << this << " id = " << id << endl;
        throw Bad();
    }

    ~Foo()
    {
        cout << "dtor.this = " << this << " id = " << id << endl;
    }

    virtual void print() { }

    static void* operator new(size_t size);
    static void* operator new(size_t size, void* start);
    static void* operator new(size_t size, long extra);
    static void* operator new(size_t size, long extra, char init);
    // static void* operator new(long extra, size_t size);
    // static void operator delete(void* pdead);
    static void operator delete(void* pdead, size_t size);
    static void operator delete(void* pdead, void* start);
    static void operator delete(void* pdead, long extra);
    static void operator delete(void* pdead, long extra, char init);
};

// 1
void* Foo::operator new(size_t size)
{
    Foo* p = (Foo*)malloc(size);
    cout << "new size = " << size << endl;
    return p;
}

// 2
void* Foo::operator new(size_t size, void* start)
{
    return start;
}

// 3
void* Foo::operator new(size_t size, long extra)
{
    return malloc(size + extra);
}

// 4
void* Foo::operator new(size_t size, long extra, char init)
{
    return malloc(size + extra);
}

// 5 第一个参数类型必须是 size_t 否则编译出错
// void* Foo:operator new(long extra, size_t size)
// {
//     return malloc(extra + size);
// }

// 1
void Foo::operator delete(void* pdead, size_t size)
{
    cout << "delete size = " << size << endl;
    free(pdead);
}

// 2
void Foo::operator delete(void* pdead, void* start)
{
    cout << "operator delete(void*, void*)" << endl;
}

// 3
void Foo::operator delete(void* pdead, long extra)
{
    cout << "operator delete(void* pdead, long extra)" << endl;
}

// 4
void Foo::operator delete(void* pdead, long extra, char init)
{
    cout << "operator delete(void* pdead, long extra, char init)" << endl;
}

int main(void)
{
    Foo start;
    Foo* p1 = new Foo;
    cout << endl;
    Foo* p2 = new (&start)Foo;
    cout << endl;
    Foo* p3 = new (100)Foo;
    cout << endl;
    Foo* p4 = new (100, 'A')Foo;
    cout << endl;
    // Foo* p5 = new Foo(1);
    // cout << endl;
    // Foo* p6 = new (&start)Foo(2);
    // cout << endl;
    // Foo* p7 = new (100)Foo(3);
    // cout << endl;
    Foo* p8 = new (100, 'A')Foo(4);

    delete p1;
    delete p2;
    delete p3;
    delete p4;

    return 0;
}

// 测试结果,自己的使用的 clang 编译器没显示调用 delete()

C++ 基础 候捷老师(上)笔记

发布了5 篇原创文章 · 获赞 5 · 访问量 1773

猜你喜欢

转载自blog.csdn.net/qq_38591886/article/details/105035682