C/C++语法
const关键字
- 修饰变量,说明该变量不可以被改变;
- 修饰指针,分为指向常量的指针(pointer to const)和自身是常量的指针(常量指针,const pointer);
- 修饰引用,指向常量的引用(reference to const),用于形参类型,即避免了拷贝,又避免了函数对值的修改;
- 修饰成员函数,说明该成员函数内不能修改成员变量。
mutable关键字
- 在编程中,
mutable
关键字通常用于修饰类的成员变量,特别是在使用const
成员函数时。它的作用是允许在const
成员函数中修改被mutable
修饰的成员变量的值,即使这个函数是const
的,也可以修改mutable
变量。
#include <iostream>
using namespace std;
class A
{
public:
A() : a(10) {}
//加了const说明函数参数类型是const A* const this,只能调用const类型的函数
void func1()const { func3(); }
//这里没加const可以调用const和非const
void func2() { func1(); func4();}
//修改mutable变量
void func3()const { b = 10;};
void func4(){}
//const 修饰只能使用初始化列表赋值
const int a;
//mutable修饰的成员变量可以在const成员函数中改变
mutable int b;
//static 修饰的变量属于静态变量不属于某一个对象属于整个类,必须在类外初始化
static int c;
};
int A::c = 20; // 在类外初始化静态成员变量c
int main()
{
//指针常量,指针指向不可以修改,但是指向的内容可以修改
int* const p = new int(20);
*p = 30;
//常量指针,指针指向可以修改,但是指向的内容不可以修改
const int* q = new int(30);
q = new int(50);
return 0;
}
static关键字
- 修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在 main 函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值初始化它。
- 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命名空间里的函数重名,可以将函数定位为 static。
- 修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员。
- 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问非静态成员。
class A
{
public:
//静态成员函数作用域属于类,可以通过类型直接访问
//静态成员函数只能调用静态函数和使用静态变量
static void func() { a = 30; func4();}
//const函数可以使用const成员函数和静态函数和静态变量
void func2()const { func5(); func(); a = 30; }
//普通函数都可以使用
void func3() { func(); func2(); b = 30; a = 50; }
//原理是函数参数不同
//static函数参数没有this指针
static void func4(){}
void func5()const {}
static int a;
int b = 20;
};
int A::a = 10;
friend关键字
- 可以让一个全局函数访问某一个类的保护或私有成员
- 允许一个函数或另一个类访问当前类的私有成员。通过在类定义中声明某个函数或类为friend,该函数或类就可以访问当前类的私有成员,即使这些成员在普通情况下是不可访问的。
#include <iostream>
using namespace std;
class B;
class A;
class C;
class C
{
public:
void func(B& b);
};
class A
{
public:
//声明func函数
void func(B& b);
private:
int a = 10;
};
class B
{
public:
//声明A的func函数是B的友元函数,也就是func函数可以访问B的保护私有成员
friend void A::func(B& b);
//声明类C为B的友元类,类C中的所有函数可以访问B的保护私有成员
friend class C;
//声明一个全局函数,该函数可以访问B的保护私有成员
friend void func2(B& b);
private:
int b = 20;
};
//友元函数类外实现 !!!
void A::func(B& b)
{
b.b;
}
//友元函数类外实现 !!!
void C::func(B& b)
{
b.b;
}
//友元函数类外实现 !!!
void func2(B& b)
{
b.b;
}
int main()
{
A a;
B b;
C c;
a.func(b);
c.func(b);
func2(b);
return 0;
}
volatile关键字
- volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。
- volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值)
- const 可以是 volatile (如只读的状态寄存器)
- 指针可以是 volatile
- volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
sizeof()关键字
- sizeof 对数组,得到整个数组所占空间大小。
- sizeof 对指针,得到指针本身所占空间大小。
//数组会自动退化为指针!!!
void func(char c[100])
{
//8
cout << sizeof(c) << endl;
}
char c[10];
//10
cout << sizeof(c) << endl;
func(c);
封装继承多态
#include <iostream>
using namespace std;
class Base
{
public:
Base():p(new int(0)){ cout << "父类默认构造" << endl; }
Base(int a) :p(new int(a)){ cout << "父类有参数构造" << endl; }
Base(const Base& rhs):p(new int(*rhs.p)) { cout << "父类拷贝构造" << endl; }
Base& operator=(const Base& rhs)
{
if (this != &rhs)
{
*p = *rhs.p;
}
cout << "父类赋值函数" << endl;
return *this;
}
virtual ~Base()
{
if (p)
delete p;
p = 0;
cout << "父类析构" << endl;
}
//虚函数
virtual void func(){}
//纯虚函数
//有纯虚函数的类叫做抽象类,不能够实例化对象
virtual void func2() = 0;
int* p;
};
class Derived : public Base
{
public:
//在 C++ 中,子类的构造函数必须要调用一个父类的构造函数,无论是显式还是隐式的。
// 如果在子类构造函数中没有显式地调用父类的构造函数,则会自动调用父类的默认构造函数(无参数的构造函数)。
// 如果父类没有默认构造函数,而子类的构造函数又没有显式地调用任何其他父类的构造函数,则会导致编译错误。
//这意味着,你总是需要确保父类有一个可以被调用的构造函数,无论是通过定义一个默认构造函数,
// 还是通过在子类的构造函数中显式调用一个存在的父类构造函数。
Derived():Base(), q(new int(0)) { cout << "子类默认构造" << endl; }
Derived(int r,int l) :Base(r),q(new int(l)){ cout << "子类有参数构造" << endl; }
Derived(const Derived& rhs):Base(rhs),q(new int(*rhs.q)) { cout << "子类类拷贝构造" << endl; }
Derived& operator=(const Derived& rhs)
{
if (this != &rhs)
{
Base::operator=(rhs);
*q = *rhs.q;
}
cout << "子类赋值函数" << endl;
return *this;
}
//重写虚函数
void func() override{}
//重写纯虚函数
void func2(){}
~Derived()
{
if (q)
delete q;
q = 0;
cout << "子类析构" << endl;
}
int* q;
};
//重载指的是函数名相同但是参数不同的函数重载
//重写指的是父类定义虚函数,子类重写父类的虚函数实现动态多态
//原理是虚函数表,每一个类都有唯一的虚函数表,每一个实例化的对象都有一个指向虚函数表的指针
int main()
{
Base* p = new Derived(10,20);
delete p;
return 0;
}
//公共基类
class N
{
public:
N(int data1, int data2, int data3) :
m_data1(data1),
m_data2(data2),
m_data3(data3)
{
std::cout << "call common constructor" << std::endl;
}
virtual ~N(){}
void display()
{
std::cout << m_data1 << std::endl;
}
public:
int m_data1;
int m_data2;
int m_data3;
};
//虚继承方式
class A : virtual public N
{
public:
A() :N(11, 12, 13), m_a(1)
{
std::cout << "call class A constructor" << std::endl;
}
~A(){}
public:
int m_a;
};
//虚继承方式
class B : virtual public N
{
public:
B() :N(21, 22, 23), m_b(2)
{
std::cout << "call class B constructor" << std::endl;
}
~B(){}
public:
int m_b;
};
// 类A和类B是虚继承方式
class C : public A, public B
{
public:
//负责对直接基类的初始化 以及虚基类的初始化
C() : A(), B(), N(31,32,33),
m_c(3)
{
std::cout << "call class C constructor" << std::endl;
}
void show()
{
std::cout << "m_c=" << m_c << std::endl;
}
public:
int m_c;
};
//此时基类N不是虚基类
class D : public N
{
public:
//负责对基类的初始化
D() :N(41, 42, 43),
m_d(4)
{
std::cout << "call class D constructor" << std::endl;
}
void show()
{
std::cout << "m_d=" << m_d << std::endl;
}
public:
int m_d;
};
int _tmain(int argc, _TCHAR* argv[])
{
C data;
//直接使用基类数据
data.m_data1 = 10;
return 0;
}
操作系统
进程是操作系统分配资源的最小单位,分配的资源包括内存,寄存器,文件描述符,环境变量,上下文等等。
线程是操作系统资源调度的最小单位,同一进程下的所有线程共享该进程的资源。。linux系统下没有进程和线程的区分,都是tsak任务结构体,只不过在一个进程中会有一个主线程。
进程间通信:管道,共享内存,消息队列,信号量,套接字,信号。
管道机制本质上是一种特殊的文件,该文件有两个端口,分别为读端口和写端口,管道机制是半双工机制也就是这两个端口不可以同时进行读写!!!所以要实现进程间的双向通信要建立两个管道!!!管道有匿名管道,适合于父子进程间通信;有名管道适合于没有关系的进程间通信。
共享内存就是创建一段内存空间,所有进程都可以进行读写操作,但是又有了新的问题,就是不同进程之间读写操作不同步,可以使用信号量来解决该同步问题。
信号量其实就是一个变量 ,我们可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为 1 的信号量。用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现进程互斥或同步。这一对原语就是 PV 操作:
- 1)P 操作:将信号量值减 1,表示申请占用一个资源。如果结果小于 0,表示已经没有可用资源,则执行 P 操作的进程被阻塞。如果结果大于等于 0,表示现有的资源足够你使用,则执行 P 操作的进程继续执行。
- 2)V 操作:将信号量值加 1,表示释放一个资源,即使用完资源后归还资源。若加完后信号量的值小于等于 0,表示有某些进程正在等待该资源,由于我们已经释放出一个资源了,因此需要唤醒一个等待使用该资源(就绪态)的进程,使之运行下去。
信号是进程通信机制中唯一的异步通信机制,它可以在任何时候发送信号给某个进程。通过发送指定信号来通知进程某个异步事件的发送,以迫使进程执行信号处理程序。信号处理完毕后,被中断进程将恢复执行。用户、内核和进程都能生成和发送信号。
信号事件的来源主要有硬件来源和软件来源。所谓硬件来源就是说我们可以通过键盘输入某些组合键给进程发送信号,比如常见的组合键 Ctrl+C 产生 SIGINT 信号,表示终止该进程;而软件来源就是通过 kill 系列的命令给进程发送信号,比如 kill -9 1111 ,表示给 PID 为 1111 的进程发送 SIGKILL 信号,让其立即结束。
Socket套接字,如果想要跨网络与不同主机上的进程进行通信,那该怎么做呢?这就是 Socket 通信做的事情了(当然,Socket 也能完成同主机上的进程通信)。从计算机网络层面来说,Socket 套接字是网络通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的 IP 地址,本地进程的协议端口,远地主机的 IP 地址,远地进程的协议端口。Socket 的本质其实是一个编程接口(API),是应用层与 TCP/IP 协议族通信的中间软件抽象层,它对 TCP/IP 进行了封装。它把复杂的 TCP/IP 协议族隐藏在 Socket 接口后面。对用户来说,只要通过一组简单的 API 就可以实现网络的连接。
消息传递机制(Linux 中称消息队列),比如,A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程在需要的时候自行去消息队列中读取数据就可以了。同样的,B 进程要给 A 进程发送消息也是如此。
消息队列的本质就是存放在内存中的消息的链表,而消息本质上是用户自定义的数据结构。如果进程从消息队列中读取了某个消息,这个消息就会被从消息队列中删除。
消息队列是消息的链接表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。
- 1、消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
- 2、消息队列独立于发送与接收进程,进程终止时,消息队列中的内容不会被删除
- 3、消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按照消息的类型读取
计算机网络
分层 | 作用 | 协议 |
---|---|---|
物理层 | 通过媒介传输比特,确定机械及电气规范(比特 Bit) | RJ45(以太网网线)、CLOCK、IEEE802.3(中继器,集线器) |
数据链路层 | 将比特组装成帧和点到点的传递(帧 Frame) | PPP、FR、HDLC、VLAN、MAC(网桥,交换机) |
网络层 | 负责数据包从源到宿的传递和网际互连(包 Packet) | IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP(路由器) |
运输层 | 提供端到端的可靠报文传递和错误恢复( 段Segment) | TCP、UDP、SPX |
会话层 | 建立、管理和终止会话(会话协议数据单元 SPDU) | NFS、SQL、NETBIOS、RPC |
表示层 | 对数据进行翻译、加密和压缩(表示协议数据单元 PPDU) | JPEG、MPEG、ASII |
应用层 | 允许访问OSI环境的手段(应用协议数据单元 APDU) | FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS |
物理层
- 传输数据的单位:比特
- 数据传输系统:源系统(源点、发送器) --> 传输系统 --> 目的系统(接收器、终点)
通道:
- 单向通道(单工通道):只有一个方向通信,没有反方向交互,如广播
- 双向交替通信(半双工通信):通信双方都可发消息,但不能同时发送或接收
- 双向同时通信(全双工通信):通信双方可以同时发送和接收信息
通道复用技术:
- 频分复用(FDM,Frequency Division Multiplexing):不同用户在不同频带,所用用户在同样时间占用不同带宽资源
- 时分复用(TDM,Time Division Multiplexing):不同用户在同一时间段的不同时间片,所有用户在不同时间占用同样的频带宽度
- 波分复用(WDM,Wavelength Division Multiplexing):光的频分复用
- 码分复用(CDM,Code Division Multiplexing):不同用户使用不同的码,可以在同样时间使用同样频带通信
数据链路层
主要信道:
- 点对点信道
- 广播信道
点对点信道
- 数据单元:帧
三个基本问题:
- 封装成帧:把网络层的 IP 数据报封装成帧,
SOH - 数据部分 - EOT
- 透明传输:不管数据部分什么字符,都能传输出去;可以通过字节填充方法解决(冲突字符前加转义字符)
- 差错检测:降低误码率(BER,Bit Error Rate),广泛使用循环冗余检测(CRC,Cyclic Redundancy Check)
点对点协议(Point-to-Point Protocol):
- 点对点协议(Point-to-Point Protocol):用户计算机和 ISP 通信时所使用的协议
广播信道
广播通信:
- 硬件地址(物理地址、MAC 地址)
- 单播(unicast)帧(一对一):收到的帧的 MAC 地址与本站的硬件地址相同
- 广播(broadcast)帧(一对全体):发送给本局域网上所有站点的帧
- 多播(multicast)帧(一对多):发送给本局域网上一部分站点的帧
数据库
数据库主要分为几种类型,每种都有其特定的应用场景和优势。
- 关系型数据库(RDBMS),使用表格和行来组织数据,支持SQL查询语言。MySQL, PostgreSQL, Oracle, SQL Server。
- 非关系型数据库(NoSQL),不使用传统的表格模式,通常用于处理大规模数据集,灵活的数据模型。MongoDB, CouchDB,Redis, DynamoDB等。
- 内存数据库,数据主要存储在内存中,提供极高的处理速度。Redis, Memcached。
- 分布式数据库,运行在多个计算机或服务器上,可以处理大规模的数据并提供高可用性。Cassandra, CockroachDB, Google Spanner。
- 时间序列数据库(TSDB),专门为处理时间标记数据设计,适用于监控,日志数据,市场数据等。InfluxDB, TimescaleDB。
一些最重要的 SQL 命令:
1. **SELECT**
- 示例:`SELECT name, age FROM users WHERE age > 18 ORDER BY name;`
- 功能:从`users`表中检索年龄大于18的所有用户的名字和年龄,并按名字排序。
2. **UPDATE**
- 示例:`UPDATE users SET email = 'newemail@example.com' WHERE id = 1;`
- 功能:更新`users`表中`id`为1的用户的电子邮件地址。
3. **DELETE**
- 示例:`DELETE FROM users WHERE last_login < '2022-01-01';`
- 功能:删除`users`表中最后登录时间早于2022年1月1日的所有用户。
4. **INSERT INTO**
- 示例:`INSERT INTO users (name, email, age) VALUES ('John Doe', 'john.doe@example.com', 28);`
- 功能:向`users`表中插入一个新用户,包括其姓名、电子邮件和年龄。
5. **CREATE DATABASE**
- 示例:`CREATE DATABASE mydatabase;`
- 功能:创建一个名为`mydatabase`的新数据库。
6. **ALTER DATABASE**
- 示例:`ALTER DATABASE mydatabase SET read_only = true;`
- 功能:修改`mydatabase`数据库,设置为只读模式。
7. **CREATE TABLE**
- 示例:`CREATE TABLE employees (id INT PRIMARY KEY, name VARCHAR(100), salary DECIMAL(10, 2));`
- 功能:创建一个新表`employees`,包含`id`(主键)、`name`和`salary`列。
8. **ALTER TABLE**
- 示例:`ALTER TABLE employees ADD COLUMN department VARCHAR(50);`
- 功能:在`employees`表中添加一个新列`department`。
9. **DROP TABLE**
- 示例:`DROP TABLE old_data;`
- 功能:删除名为`old_data`的表及其所有数据。
10. **CREATE INDEX**
- 示例:`CREATE INDEX idx_name ON users (name);`
- 功能:在`users`表的`name`列上创建一个索引,以加快基于名字的查询速度。
11. **DROP INDEX**
- 示例:`DROP INDEX idx_name ON users;`
- 功能:删除`users`表上名为`idx_name`的索引。
Comments NOTHING