侯捷C++个人学习笔记面向对象Part2

conversion function,转换函数

转换函数详细讲解链接
在C++中 当类的构造函数参数只有一个内置类型的形参或除了第一个形参外其他的参数都有默认值时,允许把这种内置类型赋值给类对象,这是一种隐试类型转换。
在这里插入图片描述
fraction分数,分子除以分母就是一个double值
operator double函数的意思就是当fraction对象需要变成double的时候就可以调用此函数,由于分子分母都不会改变因此给operator double函数加上const。此时当fraction对象参与double时都会自动调用此函数变成double类型
只要你认为合理,你就可以添加转换函数。

double d = 4 + f;这一语句会首先查找Fraction是否有重载操作符 operator + (double, Fraction) 的函数,由于没有,所以调用会转换函数operator double() const。

one-argument ctor,仅需要一个实参的构造函数

non-explicit,不明确的

表示在某些情况下可以隐性的将非fraction对象通过构造函数转换成fraction对象
在这里插入图片描述
d2=f+4,+符号左边是fraction对象,fraction类中有写operator+的函数必须与相同的fraction对象相加,因此考虑将4转为fraction对象于是调用蓝色部分的构造函数将4转换成fraction(4,1)
在这里插入图片描述
如果这两个函数并存,这时候编译器就不知道转换f还是4就会报错
只要某个操作对于编译器来说有不止一条路可行,则编译器就会报错

explicit,明确的

表示不可以隐性的转换对象,例如不能再将3转换成3/1的fraction对象
在这里插入图片描述
此时4就不会再变成fraction对象
在这里插入图片描述
bool表示vector(容器)传出来的值是真或假,对操作符[]重载的意义在于判断传出的某一个位置的值如第三个位置或者第一百个位置的值是真或假,而传出来的是reference对象,此对象对应的是_bit_reference,用这个类代表/代理本应该传出的值即bool值。
果然再_bit_reference中有将reference对象转换成bool类型的函数

pointer-like classes,关于智能指针

在这里插入图片描述
一个C++的class会像两种东西
1.像指针
2.像函数
像指针的class其中一定会有一个真正的指针,如上图所示指针所能做出来的动作,这个class也必须要做出来。new Foo得到一个指针放到shared_ptr对象sp中,sp通过构造函数创建出指向Foo对象空间的指针。

智能指针类中一定要有*和->
sp转换成px,其中的星号已经被消耗掉了
->有一个特殊的行为,消耗->符号得到的东西要继续用->符号作用下去

pointer-like classes,关于迭代器

在这里插入图片描述
容器本身带着迭代器,迭代器也是一种智能指针,但与普通智能指针不一样。
迭代器常用于遍历容器
在这里插入图片描述
标准库容器的链表如上图所示,链表的迭代器为node,node就是上一幅图中的link_type node。
我们使用迭代器的时候,使用星号的时候就表示我们想要获取它的值(即node对应的data)。
->重载中的operator*()用的是上面那个函数

f

### 关于侯捷 C++ 系列课程学习笔记 #### 内存管理和 `std::allocator` 在探讨内存管理时,`std::allocator` 是一个重要的概念。它提供了一种通用的方式来进行动态内存分配和释放操作[^1]。通过使用 `std::allocator`,可以更灵活地控制容器内部对象的创建与销毁。 ```cpp #include <memory> using namespace std; int main() { allocator<int> alloc; const int n = 1000; int* p = alloc.allocate(n); // 构造元素 uninitialized_fill_n(p, n, 0); // 销毁并回收内存 destroy_n(p, n); alloc.deallocate(p, n); } ``` 这段代码展示了如何利用 `std::allocator` 来手动管理一块整型数据的空间,并对其进行初始化以及最终清理工作。 #### 使用迭代器简化输入处理 对于从标准输入流读取数值并将这些值存储至目标容器的操作,可以通过组合 `istream_iterator` 和算法库中的 `copy()` 函数来实现简洁高效的解决方案[^2]: ```cpp #include <iostream> #include <iterator> #include <vector> #include <algorithm> using namespace std; int main(){ vector<double> c; istream_iterator<double> eos; // 表示结束标记 istream_iterator<double> iit(cin); // 创建基于cin的输入迭代器 copy(iit, eos, back_inserter(c)); // 将所有输入复制到向量c中 } ``` 此程序片段能够方便地接收来自用户的多个浮点数作为输入,并自动将其追加到指定的目标集合内而无需显式循环结构。 #### 移动语义的重要性及其应用 当涉及到像 `std::vector` 这样的序列式容器时,确保自定义型的移动构造函数和赋值运算符被声明为 `noexcept` 至关重要。这不仅有助于提高性能,还可能影响某些 STL 容器的行为逻辑,比如扩容机制会优先考虑调用 noexcept 的版本以减少异常风险[^3]。 ```cpp class MyClass { public: MyClass(MyClass&& other) noexcept : member(std::move(other.member)) {} MyClass& operator=(MyClass&& other) noexcept { if (this != &other){ member = std::move(other.member); } return *this; } private: string member; }; ``` 上述实现了无抛出保证的右值引用重载方法,从而使得该型更适合用于频繁变动大小的数据结构之中。 #### 初始化列表 (`initializer_list`) 及其特性 最后,在介绍现代 C++ 特性的过程中不得不提到 `initializer_list`。这是一种特殊的模板参数形式,允许我们采用花括号语法传递一组同质化的初始值给构造函数或其他接受此参数的地方[^4]。值得注意的是,尽管看起来像是拥有自己的副本,实际上 initializer_list 并不持有任何实际的对象实例——它仅仅是指向原始数组的一个视图而已。 ```cpp template<typename T> void print(const initializer_list<T>& ilist){ for(auto elem : ilist) cout << elem << " "; } // 调用方式如下所示: print({1, 2, 3}); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值