C++ 类的流插入和流提取运算符为什么要声明为友元函数

友元函数版代码class AClass { private: int _count; std::string _str; std::vector<int> _vec; public: friend std::ostream &operator<<(std::ostream &os, const AClass &a) { os << "AClass: count = " << a._count << ", str = " << a._str << ", vec size = " << a._vec.size(); return os; } }; 为什么要声明为友元函数先理解一下友元函数,它实际上是一个普通函数,不属于类成员,但它又是一个特殊的普通函数,因为它可以访问类的私有成员。因此 operator<< 和 operator>> 声明为友元函数的目的很明显,就是为了能够访问类的私有成员。 实际上,如果它们不声明为友元函数,也是可以实现的,例如下面代码: class AClass { private: int _count; std::string _str; std::vector<int> _vec; public: std::ostream &operator<<(std::ostream &os) { os << "AClass: count = " << _count << ", str = " << _str << ", vec size = " << _vec.size(); return os; } }; 但是这样就需要特殊的方法来调用这个 operator<< 函数,因为它不再是一个普通函数,而是一个类成员函数: int main() { AClass a; a << std::cout; // 错误,不能这样调用 a.operator<<(std::cout); // 正确 return 0; } 这样显然不够直观,不是一个正常人类写的代码:) 所以,为了代码的可读性和可维护性,我们将 operator<< 和 operator>> 声明为友元函数,这样就可以直接使用 << 和 >> 运算符来操作类的对象了。 ...

2024年06月25日 · 1 min · Cassius0924

Socket 编程之 IO 多路复用学习笔记

什么是 IO 多路复用?阻塞 IO 与 非阻塞 IO我们先了解一下阻塞 IO,阻塞 IO 是指应用程序在读写数据时,如果没有数据可读或者写,应用程序会一直 阻塞在那里 ,直到有数据可读或者写。 与它相反的是非阻塞 IO,是指应用程序在读写数据时,无论是否有数据可读写,都 立即返回 ,若没有数据可读写将会返回一个错误码,通过不断轮询来检查是否有数据可读或者写。 IO 多路复用由于 Scoket 默认是阻塞 IO,所以很多初学者在处理多个连接时,会为每个连接创建一个线程来处理,但这样做会引起 CPU 的上下文切换,降低系统的性能。 有一种更“优雅”的方式,那就是 IO 多路复用,也称为事件驱动模型(Event-driven IO)。IO 多路复用是指内核一旦发现进程指定的一个或者多个 IO 事件已经就绪,就通知该进程。IO 多路复用模型中,只需要一个线程就可以同时处理多个连接。 通俗易懂的说,IO 多路复用就是将多个 IO 事件交给内核,内核帮我们监听这些 IO 事件,当有 IO 事件就绪时,内核会通知我们,我们只需要处理就绪的 IO 事件即可。 IO 多路复用的优点 一个线程可以同时处理多个连接,减少线程的创建和销毁 降低了系统开销,提高了系统的并发性能 IO 多路复用的实现方式 select poll epoll (Linux) kqueue (FreeBSD) IOCP(Windows) 其中 epoll 是 Linux 下的 IO 多路复用机制,kqueue 是 FreeBSD(macOS 就属于 FreeBSD)下的 IO 多路复用机制。 下面的伪代码是 IO 多路复用的最基本实现方式: ...

2024年06月24日 · 7 min · Cassius0924

搭建自动化部署的 GitHub.io 个人静态博客指南

本文章主要介绍如何使用 GitHub Actions 实现基于 MkDocs 的 GitHub.io 个人静态博客的自动化部署。 本指南主要分为以下几个部分: 创建 GitHub 仓库 创建 MkDocs 项目 配置 GitHub Actions 部署到 GitHub Pages 创建 GitHub 仓库由于我们的博客是托管在 GitHub io 上的,所以我们需要一个 GitHub 仓库来存放我们的 MkDocs 博客。 创建仓库首先,我们需要在 GitHub 上创建一个新的仓库,仓库名可以是 <username>.github.io,其中 <username> 是你的 GitHub 用户名。 克隆仓库然后,我们需要将这个仓库克隆到本地: git clone <repository-url> cd <repository-name> 创建 MkDocs 项目安装 MkDocsMkDocs 是一个 Python 项目使用 pip 安装: pip install mkdocs 我们需要创建一个 MkDocs 项目,可以使用 MkDocs 官方提供的模板来创建。直接在仓库根目录执行以下命令即可: mkdocs new . 然后,我们需要安装 MkDocs Material 主题。当然我们也可以选择其他主题,可以在 MkDocs 的 WiKi 查看更多主题。 ...

2024年06月17日 · 3 min · Cassius0924

Windows Socket API 和 Linux Socket API

本文章主要介绍 Windows 下和 Linux 下的 Socket 编程区别,即 Windows Socket API 和 Linux Socket API 的区别。 头文件Windows 环境下的 Socket 编程需要以下头文件: <WinSock2.h> <WS2tcpip.h> 笔记 如果使用 MSVC 编译器,那么还需要使用预处理指令 #pragma comment(lib, "Ws2_32.lib") 来链接 Ws2_32.lib 库。 ...

2024年06月16日 · 2 min · Cassius0924

Windows VSCode 使用 JetBrians Mono 字体

本文主要介绍如何在 Windows 系统下的 Visual Studio Code 中使用 JetBrians Mono 字体。 下载字体可能你跟着网上很多教程一样,一上来就在 VS Code 中设置字体,结果发现设置不生效,这是因为你没有安装 JetBrians Mono 字体。 JetBrians Mono 字体下载地址:JetBrainsMono 安装字体下载字体后,解压缩,进入 ttf 文件夹,找到 JetBrainsMono-Regular.ttf 文件,双击打开,点击安装即可。当然你也可以全部字体都安装 :) 设置 VS Code打开 VS Code 的设置,搜索 editor.fontFamily,将其值设置为 JetBrains Mono,如下图所示: 重启 VS Code最后一步,重启 VS Code 即可。

2024年06月16日 · 1 min · Cassius0924

解决 “warning C4819- 该文件包含不能在当前代码页(936)中表示的字符” 问题指南

起因是因为我在对我的 C++ 项目进行跨平台适配,从 macOS 平台移植到 Windows 平台时,在使用 Cmake + MSVC 编译后,出现了这个问题。 问题原因这是由于 Windows 平台默认使用的是 GBK 编码,而 macOS 平台上使用的是 UTF-8 编码。 解决方法方法一在 CMakeLists.txt 文件中添加如下代码: add_compile_options("$<$<C_COMPILER_ID:MSVC>:/source-charset:utf-8>") 方法二在 CMakeLists.txt 文件中添加如下代码: if(MSVC) target_compile_options(<你的项目名> PRIVATE "/utf-8") endif()

2024年06月16日 · 1 min · Cassius0924

C# Protobuf 接收数据并解析数据

在流里读出数据后,需要将数据包大小缩短成有效大小,即 bytesRead 长度。 下面是 C# 端接收并解析数据的示例代码: private void ReceiveMessage() { stream = client.GetStream(); int bytesRead; while (isKeepReading) { if (stream.CanRead) { buffer = new byte[client.ReceiveBufferSize]; bytesRead = stream.Read(buffer, 0, client.ReceiveBufferSize); if (bytesRead > 0) { MemoryStream protoStream = new MemoryStream(buffer,0, bytesRead); Cas.Proto.DataMessage dataMessage = Cas.Proto.DataMessage.Parser.ParseFrom(protoStream); switch (dataMessage.Type) { case DataMessage.Types.Type.Mesh: Debug.Log("Mesh类型"); break; default: break; } } } } }

2024年06月16日 · 1 min · Cassius0924

C++ 中位运算的妙用:与运算和或运算的合并标志位

当我们处理程序中的多个标志位时,将它们合并成一个整数是一种常见的技巧。这种做法不仅有助于提高代码的可读性,还使得对多个标志位进行操作更为方便。 在C++中,可以使用按位或(|)运算符来实现这一功能。 合并标志位的基本思想在C++中,合并标志位的基本思想是将多个标志位的二进制表示中的相应位进行按位或运算,形成一个包含所有标志位信息的整数。这样,就能够用一个整数表示多个不同的状态或选项。 代码示例#include <iostream> int main() { // 定义三个标志位 const int FLAG_A = 0b0001; const int FLAG_B = 0b0010; const int FLAG_C = 0b0100; // 合并标志位 int flags = FLAG_A | FLAG_C; // 检查是否设置了某个标志位 if (flags & FLAG_A) { // True std::cout << "FLAG_A is set." << std::endl; } if (flags & FLAG_B) { // False std::cout << "FLAG_B is set." << std::endl; } if (flags & FLAG_C) { // True std::cout << "FLAG_C is set." << std::endl; } return 0; } 在这个示例中,首先定义了三个标志位 FLAG_A、FLAG_B 和 FLAG_C,它们分别对应二进制的 0001、0010 和 0100。然后,使用 | 运算符将 FLAG_A 和 FLAG_C 合并成 flags。 接下来,使用按位与运算符 & 来检查 flags 中是否设置了每个标志位。如果某个标志位被设置,相应的条件语句将会执行。 优点与用途 可读性提高: 将多个标志位合并成一个整数可以提高代码的可读性。通过使用有意义的常量名称,可以更清晰地了解整数表示的含义。 便于操作: 合并后的整数可以方便地进行各种按位操作,如按位与、按位或等,而无需单独处理每个标志位。 节省内存: 在某些情况下,将多个标志位合并成一个整数可能节省内存,特别是当标志位数量较多时。 在实际编码中,合并标志位是一种常见的编程技巧,适用于需要处理多个二进制状态的情况。这种技术不仅简化了代码,还使得代码更易维护和扩展。

2024年06月16日 · 1 min · Cassius0924

Cassius0924 的 VSCode 插件

# .NET Install Tool for Extenstion ABC C/C++ C/C++ Extension Pack C/C++ Themes C# C# Dev Kit CMake CMake Language Support Cmake Tools Codelf Code Runner Code Snap Code Together Color Highlight Color Picker CSS Peek D Dev Containers Docker Doxygen Documentation Genertor EFG Git Graph git-commit-plugin GitHub Copilot GitHub Copilot Chat GitHub Copilot Labs GitHub Pull Resquest and Issues HI IntelliCode API Usage Examples IntelliCode for C# Dev Kit IntelliJ IDEA New UI Theme J Jetbrains Fleet Theme JetBrains Icon Theme JetBrains IDE Keymap KL Live Sever Live Share M Markdown Preview Github Styling Markdown Preview Mermaid Support Marp for VS Code MASM masm-code MASM/TASM Material Icon Theme mypy NOP Pylance Python QR Remote - SSH: Editing Configuration Files Remote - Development Remote Explorer REST API Ruff S Slidev T TODO Highlight v2 UV Vim VSCode DOSBox VSCode Git Commit Message W WSL XYZ Marp for VS Code

2024年06月16日 · 1 min · Cassius0924

Google Coral Dev Board 修改风扇转动温度阈值指南

Google Coral Dev Board 是一款功能强大的开发板,可用于构建机器学习应用程序。该板配备了 Edge TPU,这是一款专门用于机器学习任务的加速器。Edge TPU 非常高效,但它也可能会产生热量。如果温度过高,Edge TPU 可能会降频或关闭。 查看目前 TPU 温度使用命令查看目前开发板核心 TPU 的温度,输出温度为1000倍的摄氏度。 cat /sys/class/thermal/thermal_zone0/temp 如输出54000,则代表当前温度为54摄氏度。 修改散热器温度阈值禁用热管理: echo "disabled" > /sys/devices/virtual/thermal/thermal_zone0/mode 修改散热器温度阈值为50摄氏度 echo 50000 > /sys/devices/platform/gpio_fan/hwmon/hwmon0/fan1_target

2024年06月16日 · 1 min · Cassius0924