# Cplus learning **Repository Path**: ding-xueshuang/cplus-learning ## Basic Information - **Project Name**: Cplus learning - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-31 - **Last Updated**: 2024-11-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # C++入门 ## 写在前面 这个仓库主要用于本人学习C++编程,内容一部分属于自己独创,一部分会借鉴比如:菜鸟教程、github、博客园或者是一些大佬的笔记。无任何商业盈利目的。 ## 一、基本概念与语法 ### (1)预处理 如`define`宏 ```C++ # include using namespace std; # define PI 3.1415926 // 1 宏定义 # define Max(a,b)(a>b?a:b) // 2 参数宏 int main(){ int r = 2; cout<<"circle's area is:"< # include using namespace std; class Student { public: int age; float height; //成员函数 void get_student_inf(void); void set_student(int a,float h); }; void Student::get_student_inf(void) { cout<<"student age:"< # include using namespace std; class Student { private: int age; float height; //成员函数 public: void get_student_inf(void); void set_student(int a,float h); Student(); //构造函数 }; Student::Student() { cout<<"调用Student类的构造函数"< # include using namespace std; class Student { private: int age; float height; //成员函数 public: void get_student_inf(void); void set_student(int a,float h); // Student(); //默认类的构造函数 无参数 Student(int a,int h); }; Student::Student(int a, int h) { cout<<"调用Student类带参数的构造函数"< # include using namespace std; class Student { private: int age; float height; //成员函数 public: void get_student_inf(void); void set_student(int a,float h); // Student(); //默认类的构造函数 无参数 Student(int a,int h); // 带参数的构造函数 Student(const Student &obj); //拷贝构造函数 ~Student(); // 析构函数 }; Student::Student(int a, int h) // 带参数的构造函数 { cout<<"调用Student类带参数的构造函数"< # include using namespace std; class Student { private: int age; float height; //成员函数 public: void get_student_inf(void); void set_student(int a,float h); // Student(); //默认类的构造函数 无参数 Student(int a,int h); // 带参数的构造函数 ~Student(); }; Student::Student(int a, int h) { cout<<"调用Student类带参数的构造函数"< # include using namespace std; class Student { private: int age; float height; //成员函数 public: friend void get_inf(Student s); // friend 关键字声明get_inf()为友元函数,不属于Student void set_student(int a,float h); // Student(); //默认类的构造函数 无参数 Student(int a,int h); // 带参数的构造函数 Student(const Student &obj); //拷贝构造函数 ~Student(); // 析构函数 }; Student::Student(int a, int h) // 带参数的构造函数 { cout<<"调用Student类带参数的构造函数"< # include using namespace std; class Student { private: int age; float height; //成员函数 public: friend void get_inf(Student s); // friend 关键字声明get_inf()为友元函数,不属于Student void set_student(int a,float h); void get_student_inf(void); // Student(); //默认类的构造函数 无参数 Student(int a,int h); // 带参数的构造函数 Student(const Student &obj); //拷贝构造函数 ~Student(); // 析构函数 }; Student::Student(int a, int h) // 带参数的构造函数 { cout<<"调用Student类带参数的构造函数"<age<<","<<"height:"<height<get_student_inf(); return 0; //方法2 Student *p = new Student(23,165); ////指针p指向 new Student(23,165)的地址 p->get_student_inf(); delete p; } ``` 函数可接受一个类的指针来访问类中的方法。比如: ```C++ // 综上class Student 类已经定义 void print_Student(Student *p) { p->get_student_inf(); } int main() { Student s4(19,166); print_Student(&s4); return 0; } ``` #### (7)类中的静态成员 ##### 静态成员变量 静态成员变量的关键字是static 表明无论创建多少个类的对象,静态成员都只有一个副本。这意味着,静态成员变量是被类的多个对象共享的。 ```C++ # include # include using namespace std; class Student { private: int age; float height; //成员函数 public: static int Group; // 静态成员变量 friend void get_inf(Student s); // friend 关键字声明get_inf()为友元函数,不属于Student void set_student(int a,float h); void get_student_inf(void); // Student(); //默认类的构造函数 无参数 Student(int a,int h); // 带参数的构造函数 Student(const Student &obj); //拷贝构造函数 ~Student(); // 析构函数 }; Student::Student(int a, int h) // 带参数的构造函数 { cout<<"调用Student类带参数的构造函数"<age<<","<<"height:"<height <<","<<"Group:"<get_student_inf(); } int Student::Group = 2024; //初始化静态成员变量 int main() { Student s4(19,166); Student s5(25,186); print_Student(&s4); print_Student(&s5); return 0; } ``` ##### 静态成员函数 静态成员函数可以在类不初始化对象的前提下调用,且它只能访问静态成员变量、静态成员函数、类外的函数。因此,笔者理解静态变量与函数是类内不属于该类的数据与结构。 ``` 但注意调用静态成员变量时使用格式如下:类名::静态成员函数() ``` ```C++ void Student::get_Group() { cout<<"Group is:"< using namespace std; class printData{ public: void print(int data) { cout<<"int data:"<x+p.x; p1.y = this->y+p.y; return p1; } void print() { cout<<"(x,y)="<<"("< using namespace std; class Animal { public: void eat(); void sleep(); protected: void fur(); private: void no_fur(); }; //cat 公有继承 自Animal class Cat: public Animal{ public: void Miao(); }; void Animal::eat() //基类方法 { cout<<"it can eat!"< using namespace std; // 基类1 Shape class Shape { public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } protected: int width; int height; }; // 基类2 PaintCost class PaintCost { public: int getCost(int area) { return area * 70; } }; // 派生类 class Rectangle: public Shape, public PaintCost { public: int getArea() { return (width * height); } }; int main(void) { Rectangle Rect; int area; Rect.setWidth(5); Rect.setHeight(7); area = Rect.getArea(); // 输出对象的面积 cout << "Total area: " << Rect.getArea() << endl; // 输出总花费 cout << "Total paint cost: $" << Rect.getCost(area) << endl; return 0; } ``` ### 3、多态 多态是允许不同类的对象使用相同的接口名字,但具有不同实现的特性。 多态主要通过虚函数(Virtual Function)和抽象基类(Abstract Base Class)来实现。 虚函数允许在派生类中重写基类的方法,而抽象基类包含至少一个纯虚函数(Pure Virtual Function),不能被实例化,只能作为其他派生类的基类。 通过多态,我们可以编写更加通用、可扩展的代码,提高代码的灵活性。 #### (1)虚函数的使用 ```C++ #include using namespace std; class Shape { protected: int width, height; public: Shape(int a=0, int b=0): width(a), height(b){} // 声明虚函数 这样可以允许每个子类都有一个函数 area() 的独立实现 virtual int area() { cout<<" Shape area is:"<area(); s = &t; s->area(); return 0; } ``` 如果不声明`virtual`关键字,函数就会静态链接到基类方法,不能实现多态。 #### (1)设计抽象基类 抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。 如果类中至少有一个函数被声明为纯虚函数(“=0”),则这个类就是抽象类。比如`virtual int get_area()=0;` ```C++ # include using namespace std; class Shape // 设计抽象类 不可以被实例化对象 { protected: int width; int height; public: // 纯虚函数声明 virtual int get_area()=0; void set_width(int w) { width = w; } void set_height(int h) { height = h; } }; class Rectangle:public Shape // 只有其派生类可以被实例化对象 { public: int get_area() // 前提是派生类已经将父类的纯虚函数实现 { cout<<"Rectangle area is:"<<(width*height)< # include // 文件读写流 包含ofstream与ifstream using namespace std; int main() { char data[100]; ofstream outfile; // 创建写模式对象 outfile.open("default_file.dat"); // 以写模式打开文件 cout<<"please writing to the file:"<> data; // 从文件读取数据 cout< using namespace std; double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); } int main() { int x = 10; int y = 0; int z = 0; try { z = division(x,y); cout<< z < # include # include using namespace std; // template // 1 函数模版,自定义的函数类型 // T const& Max(T const&a,T const &b) // { // return a>b?a:b; // } template // 2 类自定义模版 class Stack { private: vector elem; // 实现可存储任何类型的vector 容器 public: void push(T const &); void pop(); T top() const; bool empty() const { return elem.empty(); } }; template void Stack::push(T const& e) { elem.push_back(e); } template void Stack::pop() { if(elem.empty()) throw out_of_range("Stack<>::pop():empty stack!"); elem.pop_back(); } template T Stack::top() const { if(elem.empty()) throw out_of_range("Stack<>::top():empty stack!"); return elem.back(); } int main() { // int i =20; // int j =30; // cout<<"Max:"< s1; s1.push(7); s1.push(4); s1.pop(); int t = s1.top(); cout<<"s1.top="< s2; s2.push("hello"); s2.push("world"); s2.pop(); s2.pop(); string st = s2.top(); cout<<"s2.top="<`是一个序列容器,用于存储动态大小的数组,允许开发者在容器的末尾快速地添加或删除元素。 ``` 1、导入: #include 2、声明:std::vector v; 3、添加元素:v.push_back(1); 4、访问:int data = v[0]; 5、获取元素数量:size_t s = v.size(); 6、清空:v.clear(); ``` ```c++ // 遍历容器 vector print_vector(vector &v) { cout<<"vector data:"; for(int i=0;i v; v.push_back(1); v.push_back(2); v.push_back(3); print_vector(v); // 输出vector的所有元素 cout< void print_prog(int &count) { mtx.lock(); // 锁定 cout<<"mutex locked"<`进行转移所有权与手动解锁。 原子操作:确保对共享数据的访问是不可分割的,即在多线程环境下,原子操作要么完全执行,要么完全不执行,不会出现中间状态。 ```c++ ``` #### (3)线程局部存储 线程局部存储允许每个线程拥有自己的数据副本。关键字thread_local。 ```c++ thread_local int thread_n = 1; void print_test() { thread_n = 10; cout<<"thread data:"< data_queue; std::mutex mtx; std::condition_variable cond_var; // 互斥锁与条件变量 实现线程同步 std::atomic done(false); // 原子布尔变量,用于标记生产者是否已经完成。 ``` ##### (2)生产者消费者构建 ``` 步骤1: 生产者开始生成数据,并将数据放入 data_queue。 消费者线程进入循环,检查 !done || !data_queue.empty()。 步骤2: 生产者生成数据并放入 data_queue,然后调用 cond_var.notify_one() 通知消费者有新数据。 消费者线程在 cond_var.wait(lock, [] { return !data_queue.empty() || done; }) 中等待,直到队列中有数据或生产者完成。 步骤3: 消费者线程从队列中取出数据并处理。 处理完数据后,消费者线程再次检查 !done || !data_queue.empty(),决定是否继续运行。 步骤4: 生产者完成生成数据,设置 done = true。 消费者线程在 cond_var.wait(lock, [] { return !data_queue.empty() || done; }) 中被唤醒,检查队列中是否有剩余数据。 如果队列为空且 done == true,消费者线程退出循环,结束运行。 ``` ```c++ // 生产者函数 void producer() { for (int i = 0; i < 10; ++i) { std::unique_lock lock(mtx); data_queue.push(i); lock.unlock(); cond_var.notify_one(); // 通知消费者有新数据 // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生成数据的时间 } done = true; // 标记生产者完成 } // 消费者函数 void consumer() { while (!done || !data_queue.empty()) { // 生产者没有生产完成 或者 共享队列不为空 std::unique_lock lock(mtx); // 消费者线程开始 cond_var.wait(lock, [] { return !data_queue.empty() || done; }); // 消费者线程等待 新数据或生产者完成 while (!data_queue.empty()) { // 当共享队列不为空 int data = data_queue.front(); data_queue.pop(); std::cout << "Consumed: " << data << std::endl; // 消费者消费共享队列 } lock.unlock(); // std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟处理数据的时间 } } int main() { std::thread producer_thread(producer); std::thread consumer_thread(consumer); producer_thread.join(); consumer_thread.join(); return 0; } ``` 运行结果如下: ``` Consumed: 0 Consumed: 1 Consumed: 2 Consumed: 3 Consumed: 4 Consumed: 5 Consumed: 6 Consumed: 7 Consumed: 8 Consumed: 9 ``` ## 九、C++标准库 ### 1、内存管理库`` 使用智能指针,来自动管理动态分类的内存。 ``` 1 std::unique_ptr:独占所有权的智能指针,同一时间只能有一个 unique_ptr 指向特定内存。 2 std::shared_ptr:共享所有权的智能指针,多个 shared_ptr 可以指向同一内存,内存在最后一个 shared_ptr 被销毁时释放。 3 std::weak_ptr:弱引用智能指针,用于与 shared_ptr 配合使用,避免循环引用导致的内存泄漏。 ``` #### (1)unique_ptr ```c++ # include # include using namespace std; class Student { public: void Print() { cout<<"class Student"< p(new Student()); // 调用类的成员函数 p->Print(); return 0; // 当 main 函数结束时,myPtr 被销毁,自动释放 MyClass 对象的内存 } ``` #### (2)shared_ptr ```c++ # include # include using namespace std; class Student { public: void Print() { cout<<"class Student"< p(new Student()); // 多个 shared_ptr 可以指向同一内存 shared_ptr p1(new Student()); shared_ptr p2 = p1; // 调用类的成员函数 p->Print(); p1->Print(); p2->Print(); return 0; } ``` ## 十、网络编程 网络编程主要使用socket抽象端口实现,其主要分为服务器端与客户端,调用socket库里的函数实现。 对于服务器端,实现: ``` 1、调用socket函数创建监听socket 2、调用bind函数将socket绑定到某个IP和端口号组成的二元组上 3、调用listen函数开启监听 4、当有客户端连接请求时,调用accept函数接受连接,产生一个新的socket(与客户端通信的socket) 5、基于新产生的socket调用send或recv函数开始与客户端进行数据交流 6、通信结束后,调用close函数关闭socket ``` 客户端实现: ``` 1、调用socket函数创建客户端socket 2、调用connect函数尝试连接服务器 3、连接成功后调用send或recv函数与服务器进行数据交流 4、通信结束后,调用close函数关闭监听socket ```