侯捷C++面向对象编程下day6

侯捷C++面向对象编程下day6

侯捷C++面向对象编程(下)课程打卡

侯捷C++面向对象编程(下)课程打卡 Day6

4. specialization 特化

4.1 全特化 full specialization

模板是泛化,特化是泛化的反面,可以针对不同的类型,来设计不同的东西

  • 其语法为template<> struct xxx<type>
1
2
3
4
5
6
7
8
9
10
11
12
13
template<>
struct hash<char>
{
...
size_t operator()(char& x) const {return x;}
};

template<>
struct hash<int>
{
...
size_t operator()(int& x) const { return x; }
};
  • 这里编译器就会用 int 的那段代码;注意:hash<int>() 是创建临时变量
1
cout << hash<int>()(1000)
4.2 偏特化 partial specialization
4.2.1 个数上的偏

例如:第一个模板参数我想针对 bool 特别设计

image-20230807155256372

注意绑定模板参数不能跳着绑定,需要从左到右

4.2.2 范围上的偏

例如:想要当模板参数是指针时特别设计

image-20230807160122944

1
2
C<string> obj1; //编译器会调用上面的
C<string*> obj2; //编译器会调用下面的

5 三个C++11新特性

5.1 variadic templates

模板参数可变化,其语法为 ... (加在哪看情况)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 当参数pack里没有东西了就调用这个基本函数结束输出
void print() {
}

// 用于打印多个参数的可变参数模板函数
template <typename T, typename... Args>
void print(const T& first, const Args&... args) {
std::cout << first << " ";
print(args...); // 使用剩余参数进行递归调用
}

int main() {
print(1, "Hello", 3.14, "World");
return 0;
}

还可以使用 sizeof...(args) 来得到参数pack里的数量

5.2 auto

编译器通过赋值的返回值类型,自动匹配返回类型

image-20230808080207006

注:下面这样是不行的,第一行编译器找不到返回值类型

1
2
auto ite; // error
ite = find(c.begin(), c.end(), target);
5.3 ranged-base for

for 循环的新语法,for(声明变量 : 容器),编译器会从容器中依次拿出数据赋值给声明变量中

1
2
3
4
5
6
7
8
9
10
for (decl : coll)
{
statement
}

//例
for (int i : {1, 3, 4, 6, 8}) // {xx,xx,xx} 也是c++11的新特性
{
cout << i << endl;
}

注意:改变原容器中的值需要 pass by reference

1
2
3
4
5
6
7
8
9
10
11
vector<double> vec;
...

for (auto elem : vec) //值传递
{
cout << elem << endl;
}
for (auto& elem : vec) //引用传递
{
elem *= 3;
}

6 多态 虚机制

直接看链接吧

https://blog.csdn.net/WJwwwwwww/article/details/132268502

7 reference、const、new/delete

7.1 reference

x 是整数,占4字节;p 是指针占4字节(32位);r 代表x,那么r也是整数,占4字节

1
2
3
int x = 0;
int* p = &x; // 地址和指针是互通的
int& r = x; // 引用是代表x

引用与指针不同,只能代表一个变量,不能改变

引用底部的实现也是指针,但是注意 object 和它的 reference 的大小是相同的,地址也是相同的(是编译器制造的假象)

1
2
sizeof(r) == sizeof(x)
&x == &r

reference 通常不用于声明变量,用于参数类型和返回类型的描述

image-20230808091745371

以下 imag(const double& im) 和 imag(const double im) 的签名signature 在C++中是视为相同的——二者不能同时存在

1
2
double imag(const double& im) /*const*/ {....}
double imag(const double im){....} //Ambiguity

注意:const 是函数签名的一部分,所以加上后是可以共存的

7.2 const

const 加在函数后面 —— 常量成员函数(成员函数才有):表示这个成员函数保证不改变 class 的 data

const object non-const object
const member function(保证不改变 data members) ✔️ ✔️
non-const member function(不保证 data members 不变) ❌ ✔️

COW:Copy On Write

多个指针共享一个 “Hello”;但当a要改变内容时, 系统会单独复制一份出来给a来改,即 COW

image-20230801101907977

在常量成员函数中,数据不能被改变所以不需要COW;而非常量成员函数中数据就有可能被改变,需要COW

1
2
3
4
5
6
7
8
9
10
11
charT
operator[] (size_type pos)const
{
.... /* 不必考虑COW */
}

reference
operator[] (size_type pos)
{
.... /* 必须考虑COW */
}

函数签名不包括返回类型但包括const,所以上面两个函数是共存的

当两个版本同时存在时,*const object* 只能调用 *const* 版本,*non-const object* 只能调用 *non-const* 版本

7.3 new delete

7.3.1 全局重载
  • 可以全局重载 operator new、operator delete、operator new[]、operator delete[]
  • 这几个函数是在 new 的时候,编译器的分解步骤中的函数,是给编译器调用的

注意这个影响非常大!

1
2
3
4
inline void* operator new(size_t size){....}
inline void* operator new[](size_t size){....}
inline void operator delete(void* ptr){....}
inline void operator delete[](void* ptr){....}
7.3.2 class中成员重载
  • 可以重载 class 中成员函数 operator new、operator delete、operator new[]、operator delete[]
  • 重载之后,new 这个类时,编译器会使用重载之后的
1
2
3
4
5
6
7
8
9
10
class Foo
{
public:
void* operator new(size_t size){....}
void operator delete(void* ptr, size_t size){....} // size_t可有可无

void* operator new[](size_t size){....}
void operator delete[](void* ptr, size_t size){....} // size_t可有可无
....
}
1
2
3
4
5
6
7
// 这里优先调用 members,若无就调用 globals
Foo* pf = new Foo;
delete pf;

// 这里强制调用 globals
Foo* pf = ::new Foo;
::delete pf;
7.3.3 placement new delete

可以重载 class 成员函数 placement new operator new(),可以写出多个版本,前提是每一个版本的声明有独特的传入参数列,且其中第一个参数必须是 size_t,其余参数出现于 new(.....) 小括号内(即 placement arguments)

1
2
3
Foo* pf = new(300, 'c') Foo; // 其中第一个参数size_t不用写
// 对应的operator new
void* operator new (size_t size, long extra, char init){....}

我们也可以重载对应的 class 成员函数 operator delete(),但其不会被delete调用,只当 new 调用的构造函数抛出异常 exception 的时候,才会调用来归还未能完全创建成功的 object 占用的内存

侯捷C++面向对象编程下day6

http://example.com/2024/07/07/C++/C-06/

作者

Pluto

发布于

2024-07-07

更新于

2026-03-26

许可协议

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...