# 侯捷cpp-oop(下) 笔记

# C++程序设计兼谈对象模型-导读

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692357997673/a8b82603-a850-4390-9610-0fd6d2852728.png align="center")

# conversion function, 转换函数

```cpp
class Fraction {
public:
    Fraction(int num, int den=1) : m_numerator(num), m_denominator(den){};
    operator double() const {
        return 1.0 * m_numerator / m_denominator;
    }
private:
    int m_numerator;
    int m_denominator;
};
```

* 转换函数没有返回值
    
* 函数名为 `operator double`
    
* no parameters
    
* 转换这个语义本身不改变成员变量，因此需要加 `const` 修饰。虽然不加 `const` 也可以通过编译。
    

# non-explicit-one-argument ctor

`Fraction(int num, int den=1)`这个ctor，是`2 parameters, 1 argument`. 只需要一个 `argument(实参)` 就可以实例化。

```cpp
class Fraction {
public:
    Fraction(int num, int den=1) : m_numerator(num), m_denominator(den){};
    Fraction operator+ (const Fraction& f) {
        return Fraction(0, 0); // ignore reality.
    }
private:
    int m_numerator;
    int m_denominator;
};

int main() {
    Fraction f(3, 5);
    Fraction d2 = f + 4;
    return 0;
}
```

`f + 4`, 会查找到 `Fraction operator+ (const Fraction& f)` 这个函数.

然后会尝试调用`non-explict ctor`把 `4` 转化为 `Fraction` 类型, 再传递进入 `operator+` .

## explict

`explict` 会告诉编译器不要进行**隐式转换**, 可以用来修饰`ctor`和`conversion function`. 如果需要进行转换，需要在调用处`显式指出`。

修饰 `conversion function` 这一点大部分资料不会指出，但其实是可行的. 可以参考 [user-defined conversion function](https://en.cppreference.com/w/cpp/language/cast_operator) .

# pointer-like classes

## 关于智能指针

一般`pointer`能做的事情，`pointer-like classes` 也可以做。因此能应用到 `pointer` 上的运算符，也可以应用到 `pointer-like classes`, 如`operator*()`、 `opreator->()`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358022881/33db3d47-6143-44fa-a268-1d82798cb41a.png align="center")

对于 `sp->method()`, 操作符 `->` 会作用在 `sp` 上， 调用 `T* shared_ptr::operator->()const`.

调用后，如果 `->` 是一般的操作符，如`*`, 会被消耗, 变为 `px method()`.

但是 `->` 有一个特性，会在有操作数存在的情况下，一直存在，因此经过一次调用后不会被消耗，仍然是 `px->method()`.

## 关于迭代器

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358029894/913718fb-7eb9-498a-9bda-c88d485eedcb.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358037459/19fd6675-32ed-45cf-a12f-2c85302caf34.png align="center")

迭代器也是一类`pointer-like class`, 使用者调用 `*` 意图获得 `data` 本身; 使用者调用 `->`, 意图获得 `data` 的地址，并且在改地址上继续复用 `->` 来进行一系列操作。

# function-like classes, 所谓仿函数

`operator()` 也叫 [function call operator](https://learn.microsoft.com/en-us/cpp/cpp/function-call-operator-parens?view=msvc-170).

只要 `class` 内部重载了 `operator()` 那么就可以称为 `functor（仿函数）`.

## 标准库中仿函数的奇特模样

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358047104/f078cf7d-bde0-47c6-bc8f-4b9bf7f846bc.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358052289/674e6f10-8d06-4996-a2ad-fe08b8e04209.png align="center")

`unary_function` 和 `binary_function` 既没有成员变量，也没有成员函数，理论上实际的大小是 `0`.

至于为什么要有 [c++ 基本概念之 functor](https://marquistj13.github.io/MyBlog/ReadingNotes/ProgrammingSkills/cplusplus/basic%20concepts%20%20functor#) 这篇文章讲的不错。

# member function, 成员模版

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358069410/d2bbc5e8-9abb-48eb-887d-11d6eff46c80.png align="center")

这样做可以让`ctor`更有 **"弹性"**, 可以接收多种类型的参数。

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358077287/6762c30d-fcb8-4922-a593-01fa8d330a60.png align="center")

# specialization, 模版特化

`泛化`和`特化`互为相反。

```cpp

#include <iostream>

template <typename Key>
class hash {};

template<>
class hash<char> { // 格式类似于这种, 把上面的不确定的 typename 拿下来, 变为确定的类型.
public:
    size_t operator() (char ch) {
        return size_t(ch);
    }
};

template<>
class hash<long> {
public:
    size_t operator() (long l) {
        return size_t(l);
    }
};

int main() {
    hash<long>()(1l);
    hash<char>()('a'); // 第一个() 构造出一个匿名对象, 第二个() 调用重载后的小括号运算符.
    return 0;
}
```

`特化` 也叫 `全特化(full specialization)`, 也有 `partial specialization`.

# partial specialization 模版偏特化

函数模版只能全特化, 而类模版可以偏特化和全特化。

特化必须在同一个命名空间下进行，但 `std` 是一个例外，用户可以特化其中的模版，但不可以添加模版。

## 个数的偏

偏特化的顺序只能从左向右绑定`模版参数`.

```cpp
template <typename T1, typename T2>
struct PPair {
    int hash() {
        std::cout << "in general hash() " << std::endl;
    }
};

template <typename T2>
struct PPair<int, T2> {
    int hash() {
        std::cout << "in <int, T2> partial hash()" << std::endl;
    }
};

int main() {
    PPair<double, float>().hash();
    PPair<int, double>().hash();
    return 0;
}
```

```plaintext
in general hash() 
in <int, T2> partial hash()
```

## 范围的偏

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358091173/3c34ccf3-c8bf-4004-bd0f-f2a4adeedcee.png align="center")

```cpp
template<typename T>
struct JoJo {
    void stand() {
        std::cout << "in general stand()" << std::endl;
    }
};

template<typename U>
struct JoJo<U*> {
    void stand() {
        std::cout << "in U* type stand()" << std::endl;
    }
};
int main() {
    JoJo<double>().stand();
    
    JoJo<double*>().stand();
    JoJo<int*>().stand();
    return 0;
}
```

```plaintext
in general stand()
in U* type stand()
in U* type stand()
```

# 模版模版参数 template template parameter

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358104571/3979ee00-c0aa-4871-9d38-2bf4ec2ca784.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358108611/90981217-2b41-4ea1-9cc3-098e2312efe6.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358112122/72092429-a869-4c34-931f-5fba35ee8cdd.png align="center")

# 关于 C++ 标准库

![](media/16921918091761.jpg align="left")

查看 C++ 版本

```cpp
    std::cout << __cplusplus << std::endl;
```

# 三个主题

## variadic templatem, 数量不定的模版参数

关键字 `typename...` 可以使用 `sizeof...(args)` 来获取剩余的参数数量。

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358124572/c61e4c20-2f72-475d-9ee9-e5ec75117e0a.png align="center")

```cpp
void print() {}

template<typename T, typename... TS>
void print(const T& firstArg, const TS&... args) {
    cout << firstArg << "\t rest number of TS is " << sizeof...(args) << endl;
    print(args...);
}


int main() {
    print(1.2, 1, "hello");
    return 0;
}
```

```plaintext
1.2      rest number of TS is 2
1        rest number of TS is 1
hello    rest number of TS is 0
```

将函数的参数分为 **一个** 和 **一包**，递归处理第一个，**一包** 的数量可以为 0, 最后递归调用到 `void print()`.

## auto

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358132327/d34cbd48-b5c8-464a-b614-5697d0e51c06.png align="center")

## range-base for

支持两种遍历, `pass by value` 和 `pass by reference`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358138064/cc08744c-f5ef-42ae-bc58-c1139f005198.png align="center")

# Reference

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358144524/b0b3ba5b-0c92-42f1-9c2e-3dedb0cb9e76.png align="center")

## reference 的常见用途

“reference是一种漂亮的pointer”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358150911/8c47dcb7-fd27-4041-b4fd-ecabc50d5e39.png align="center")

`reference` 通常不用于声明变量，而用于 `参数类型(paramters type)` 和 `返回类型(return type)` 的描述。

* `const` 也是函数签名的一部分
    

```cpp
// 这两个函数的签名不同
void m_func(const int&) {}
void m_func(const int&) const {}
```

# 复合&继承关系下的构造和析构

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358158194/55ca6fcd-3e30-4487-ae21-f7a1e5c1cd83.png align="center")

这里的结果和“面向对象(上)”里实验的结果一致。

# 关于 vptr 和 vtbl

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358170507/1017cb8d-5c7b-4242-8228-2c186838d2fa.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358175900/6f1a2f80-55bd-4924-9097-4e71fdb0b344.png align="center")

`范型`通过指针实现，是因为指针的内存大小都相同。 而在继承体系中，不同类的占用内存大小不一定相同。

动态绑定(多态、虚机制)的三个条件:

1. 指针调用
    
2. 指针向上转型 (`up-case`)
    
3. 调用的是 `virtual function`
    

# 关于 this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358183378/983dbe50-267d-47d6-8d71-446c52ffe67a.png align="center")

# 关于动态绑定

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358190030/a26d5ae7-76bd-4a90-b9e1-95048743ad6a.png align="center")

这里通过`对象调用`，而非通过指针，因此这里是 `static binding`, 调用了父类的函数，而非 `dynamic binding`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358197565/37901af3-b3b0-4cd0-b36d-159751d41b8f.png align="center")

# 谈谈 const

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358212222/dfd521bc-8f9f-4729-b9aa-08401c84e4f9.png align="center")

`函数重载` 不必考虑函数的返回值，只考虑函数签名(非返回值的部分)。

`char ch = s[5];` 和 `s[5] = 'a';` 分别调用 `const函数` 和 `非const函数`.

`常量字符串` 只调用 `const函数`, 不必考虑 `COW`.

# 关于 new, delete

`new Obj()` 是 `new expression`, 会调用 `operator new()` 来进行内存分配.

# 重载 operator new, operator delete

## 重载 ::operator new, ::operator delete, ::operator new\[\], ::operator delete\[\]

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358222062/c27635b6-d282-4ca0-bc3c-ba8b653b7ac9.png align="center")

这些函数由编译器调用。

## 重载 member operator new/delete

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358242385/58188e0d-7b95-4ae5-89fe-198e7fc91a72.png align="center")

```cpp
class Foo {
public:
    void* operator new(size_t t) {
        std::cout << "in overloading operator new()" << std::endl;
        return ::operator new(t);
    }
    void operator delete(void* ptr, size_t t) { // the second parameter size_t is optional
        std::cout << "in overloading operator delete(void*, size_t)" << std::endl;
        ::operator delete(ptr, t);
    }
    void operator delete(void* ptr) {
        std::cout << "in overloading operator delete(void*)" << std::endl;
        ::operator delete(ptr);
    }
};

int main() {
    Foo* p = new Foo();
    delete p;
}
```

```plaintext
in overloading operator new()
in overloading operator delete(void*)
```

## 重载 member operator new\[\]/delete\[\]

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358250534/0cd6d403-50ce-4d3a-9ca8-8285b8ae7179.png align="center")

# 示例

## new/delete operator

`new`, `new[]` 完成三件事情

1. 调用 malloc 分配内存(这一步由`::operator::new(size_t)`完成)，
    
2. 再调用构造函数创建对象, `A::A()`
    
3. 返回指针
    

delete, delete\[\] 完成两件事 调用析构函数(~A())，再释放内存(operator delete(a))

可以通过 `::new` , `::delete` 来绕过 `member operator new/delete`, 来使用全局默认的 **new & delete**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358264779/950c3b25-8a08-4d60-8468-4fe9d5165b50.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358268456/749156f9-e7cf-43b5-a9ab-dda15a02b4f2.png align="center")

# 重载 new(), delete() -- placement new/delete ()

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358282961/4ffc6527-d89c-4450-9f94-53996eecf52f.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358287307/5fad3f34-0dbb-4516-8ca9-6933a0ed5819.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358290311/bb59ada7-07b2-4c14-add7-d27b238779da.png align="center")

# Basic\_String 使用 new(extra) 扩充申请量

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692358297355/9cfd3c83-17fa-4ad4-b5f0-b37d1f166c68.png align="center")
