运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<iostream> #include<vector>
class Vector { private: int m_x; int m_y; public: Vector(int x,int y) { this->m_x = x; this->m_y = y; }
Vector operator+ (Vector& other) const{ return Vector{ m_x + other.m_x,m_y + other.m_y }; } friend std::ostream& operator<<(std::ostream& os, const Vector& other); };
std::ostream& operator<<(std::ostream& os,const Vector& other) {
os << other.m_x << " " << other.m_y << std::endl; return os; }
int main() { Vector v1(3, 4); Vector v2(1, 4); std::cout << v1 + v2; }
|
结果输出:4 8
模板template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <string> #include <iostream>
template<typename T,int size> class Array { private: T array[size]; public: int getSize() const { return size; } };
int main() { Array < std:: string, 5 > a; std::cout << a.getSize()<<std::endl; return 0; }
|
结果输出:5
函数指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <vector> #include <iostream>
void PrintValue(int value) { std::cout << "Value: " << value << std::endl; }
void ForEach(const std::vector<int>& values,void(*Print)(int)) { for (int value : values) Print(value); }
int main() { std::vector<int> values = { 1,3,41,1,3,6}; ForEach(values, PrintValue); return 0; }
|
结果输出:
1 2 3 4 5 6
| Value: 1 Value: 3 Value: 41 Value: 1 Value: 3 Value: 6
|
lambda 表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <vector> #include <iostream>
void ForEach(const std::vector<int>& values,void(*Print)(int)) { for (int value : values) Print(value); }
int main() { std::vector<int> values = { 1,3,41,1,3,6}; auto it = std::find_if(values.begin(), values.end(), [](int value) {return value > 3; }); std::cout << *it << std::endl;
auto lambda = [](int value) {std::cout << "Value: " << value << std::endl; }; ForEach(values, lambda);
int a = 5; auto lambda = [=](int value) {std::cout << "Value: " << a << std::endl; }; ForEach(values, lambda);
return 0; }
|
namespace
namespace存在原因:避免命名冲突,在不同的context中使用相同的符号
:::名称操作符
thread线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<iostream> #include<thread>
static int s_Finished = false; void DoWork() {
using namespace std::literals::chrono_literals;
std::cout << "Start thread id is " << std::this_thread::get_id() << std::endl; while (!s_Finished) { std::cout << "Working...\n"; std::this_thread::sleep_for(1s); }
}
int main() { std::thread worker(DoWork);
std::cin.get(); s_Finished = true;
worker.join(); std::cout << "Finished..\n"; std::cout << "Start thread id is " << std::this_thread::get_id() << std::endl;
std::cin.get(); }
|
计时器 Chrono
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include<iostream> #include<thread> #include<chrono>
int main() { using namespace std::literals::chrono_literals;
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(1s);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> duration = end - start; std::cout << duration.count() << "s" << std::endl;
std::cin.get(); }
|
输出 :1.0026s
优化…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<iostream> #include<thread> #include<chrono>
struct Timer { std::chrono::time_point<std::chrono::steady_clock>start, end; std::chrono::duration<float>duration; Timer() { start = std::chrono::high_resolution_clock::now(); } ~Timer() { end = std::chrono::high_resolution_clock::now(); duration = end - start;
float ms = duration.count() * 1000.0f; std::cout << "Time took" << ms << "ms" << std::endl; } };
void Function() { Timer timer; for (int i = 0; i < 100; i++) { std::cout << "hello" << std::endl; } }
int main() { Function();
std::cin.get(); }
|
输出:
1 2 3 4 5 6 7
| hello hello . . . hello Time took 53.99912ms
|
排序Sort()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<iostream> #include<algorithm> #include<vector> #include<functional>
int main() { std::vector<int> values = { 4,1,2,5,3 }; std::sort(values.begin(), values.end(), [] (int a,int b) { if (a == 1)return false; if (b == 1)return true; return a < b; });
for (int value : values) std::cout << value<<std::endl; }
|
输出
2 3 4 5 1
移动语义
移动语义相比于拷贝语义优势在于只用分配一次内存即可访问或者返回对象,减少开辟堆内存时间花销
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include<iostream> #include<string>
class String { public: String() = default; String(const char* string) { printf("Create!\n"); m_Size = strlen(string); m_Data = new char[m_Size]; memcpy(m_Data, string, m_Size); }
String(const String& other) { printf("Copyed!\n"); m_Size = other.m_Size; m_Data = new char[m_Size]; memcpy(m_Data, other.m_Data, m_Size); }
String(String&& other) noexcept{ printf("Moved!\n"); m_Size = other.m_Size; m_Data = other.m_Data;
other.m_Size = 0; other.m_Data = nullptr; }
~String() { printf("Destroyed!\n"); delete m_Data; } void Print() { for (uint32_t i = 0; i < m_Size; i++) putchar(m_Data[i]); printf("\n"); } private: char* m_Data; uint32_t m_Size;
};
class Entity { public: Entity(const String& name) :m_name(name) { } Entity(String&& name) :m_name((String&&)name) {
} void PrintName() { m_name.Print(); }
private: String m_name; };
int main() { Entity entity("Herrick"); entity.PrintName(); std::cin.get(); }
|
std::move
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include<iostream> #include<string>
class String { public: String() = default; String(const char* string) { printf("Create!\n"); m_Size = strlen(string); m_Data = new char[m_Size]; memcpy(m_Data, string, m_Size); }
String& operator=(String &&other)noexcept{
if (this != &other) { printf("Moved!\n");
delete m_Data;
m_Size = other.m_Size; m_Data = other.m_Data;
other.m_Size = 0; other.m_Data = nullptr; } return *this; }
~String() { printf("Destroyed!\n"); delete m_Data; } void Print() { for (uint32_t i = 0; i < m_Size; i++) putchar(m_Data[i]); printf("\n"); }
private: char* m_Data; size_t m_Size;
};
int main() { String apple = "Apple"; String dest;
std::cout << "Apple:"; apple.Print(); std::cout << "Dest:"; dest.Print();
dest = std::move(apple);
std::cout << "Apple:"; apple.Print(); std::cout << "Dest:"; dest.Print();
std::cin.get(); }
|
输出:
1 2 3 4 5 6
| Create! Apple:Apple Dest: Moved! Apple: Dest:Apple
|
Rule of Three
C++三法则(Rule of Three)指的是在定义一个包含动态内存分配的类时,必须重载以下三个函数:
- 拷贝构造函数(Copy Constructor):用于将一个已存在的对象复制到新创建的对象中。
- 拷贝赋值操作符(Copy Assignment Operator):用于将一个已存在的对象赋值给另一个已存在的对象。
- 析构函数(Destructor):用于在对象被销毁时释放动态分配的内存。
这三个函数的实现都要根据类中的成员变量进行深拷贝或移动操作,否则可能会引起内存泄漏或悬空指针等问题。
Rule of Five
C++五法则(Rule of Five)在 C++11 中增加了两个函数,即移动构造函数和移动赋值操作符:
- 拷贝构造函数(Copy Constructor):用于将一个已存在的对象复制到新创建的对象中。
- 拷贝赋值操作符(Copy Assignment Operator):用于将一个已存在的对象赋值给另一个已存在的对象。
- 移动构造函数(Move Constructor):用于将一个右值引用的对象移动到新创建的对象中,避免不必要的拷贝开销。
- 移动赋值操作符(Move Assignment Operator):用于将一个右值引用的对象赋值给另一个已存在的对象,避免不必要的拷贝开销。
- 析构函数(Destructor):用于在对象被销毁时释放动态分配的内存。
这五个函数的实现都要根据类中的成员变量进行深拷贝或移动操作,同时避免引起内存泄漏或悬空指针等问题。
顶层 Const 和 底层 Const
概念:
- 顶层
Const ,表示修饰的本身就是常量,指的是指针,通常 * 右边 - 底层
const,表示修饰的变量所指的量是常量,指的是所指变量,通常 * 左边
例:
1 2 3 4 5 6
| int a = 10;int* const b1 = &a; const int* b2 = &a; const int b3 = 20; const int* const b4 = &a; const int& b5 = a;
|
区分作用:
- 执行对象拷贝时有限制,常量的底层
const 不能赋值给非常量的底层 const - 使用命名的强制类型转换函数
const_cast 时,只能改变运算对象的底层 const
1
| const int a;int const a;const int *a;int *const a;
|
int const a和const int a均表示定义常量类型 a。const int *a,其中 a 为指向 int 型变量的指针,const 在 * 左侧,表示 a 指向不可变常量。(看成const (*a),对引用加 const )int *const a,依旧是指针类型,表示 a 为指向整型数据的常指针。(看成 const(a),对指针 const)