news 2026/6/15 11:51:21

C++ Primer 第19章:特殊工具与技术

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ Primer 第19章:特殊工具与技术

C++ Primer 第19章:特殊工具与技术


19.1 控制内存分配

19.1.1 重载 new 和 delete

// overload_new_delete.cpp -- 重载new和delete #include <iostream> #include <cstdlib> #include <cstring> #include <stdexcept> ​ // ===== 全局 new/delete 重载 ===== // 通常不建议重载全局版本,会影响所有内存分配 ​ // ===== 类级别的 new/delete 重载 ===== class MyClass { public: MyClass(int v = 0) : val_(v) { std::cout << "[构造] val=" << val_ << std::endl; } ​ ~MyClass() { std::cout << "[析构] val=" << val_ << std::endl; } ​ // 重载 operator new:分配内存 static void* operator new(std::size_t size) { std::cout << "[new] 分配 " << size << " 字节" << std::endl; void* p = std::malloc(size); if (!p) throw std::bad_alloc(); return p; } ​ // 重载 operator delete:释放内存 static void operator delete(void* p, std::size_t size) noexcept { std::cout << "[delete] 释放 " << size << " 字节" << std::endl; std::free(p); } ​ // 重载数组版本 static void* operator new[](std::size_t size) { std::cout << "[new[]] 分配 " << size << " 字节" << std::endl; void* p = std::malloc(size); if (!p) throw std::bad_alloc(); return p; } ​ static void operator delete[](void* p, std::size_t size) noexcept { std::cout << "[delete[]] 释放 " << size << " 字节" << std::endl; std::free(p); } ​ int val() const { return val_; } ​ private: int val_; }; ​ int main() { using namespace std; ​ cout << "===== 单个对象 =====" << endl; MyClass* p = new MyClass(42); // 调用 operator new,然后构造函数 cout << "val = " << p->val() << endl; delete p; // 调用析构函数,然后 operator delete ​ cout << "\n===== 对象数组 =====" << endl; MyClass* arr = new MyClass[3]; // 调用 operator new[] delete[] arr; // 调用 operator delete[] ​ return 0; }

19.1.2 定位 new(placement new)

// placement_new.cpp -- 定位new #include <iostream> #include <new> #include <string> ​ class Widget { public: Widget(const std::string& name) : name_(name) { std::cout << "[构造] " << name_ << std::endl; } ~Widget() { std::cout << "[析构] " << name_ << std::endl; } void show() const { std::cout << "Widget: " << name_ << std::endl; } ​ private: std::string name_; }; ​ int main() { using namespace std; ​ // ===== 定位new:在指定内存上构造对象 ===== // 语法:new (地址) 类型(参数) ​ // 在栈上分配内存 alignas(Widget) char buffer[sizeof(Widget)]; ​ // 在 buffer 上构造 Widget(不分配内存) Widget* p = new (buffer) Widget("栈上的Widget"); p->show(); ​ // 必须手动调用析构函数!(不能用 delete) p->~Widget(); ​ // ===== 在堆上预分配内存,然后构造 ===== void* raw = ::operator new(sizeof(Widget)); // 只分配内存 Widget* p2 = new (raw) Widget("堆上的Widget"); p2->show(); p2->~Widget(); // 手动析构 ::operator delete(raw); // 手动释放内存 ​ // ===== 对象池示例 ===== cout << "\n===== 对象池 =====" << endl; const int POOL_SIZE = 3; alignas(Widget) char pool[sizeof(Widget) * POOL_SIZE]; ​ // 在池中构造多个对象 Widget* widgets[POOL_SIZE]; for (int i = 0; i < POOL_SIZE; i++) { widgets[i] = new (pool + i * sizeof(Widget)) Widget("池对象" + to_string(i)); } ​ for (int i = 0; i < POOL_SIZE; i++) widgets[i]->show(); ​ // 手动析构(逆序) for (int i = POOL_SIZE - 1; i >= 0; i--) widgets[i]->~Widget(); ​ return 0; }

19.2 运行时类型识别(RTTI)

19.2.1 dynamic_cast

// dynamic_cast_demo.cpp -- dynamic_cast详解 #include <iostream> #include <memory> #include <string> ​ class Shape { public: virtual double area() const = 0; virtual std::string name() const = 0; virtual ~Shape() {} }; ​ class Circle : public Shape { public: Circle(double r) : radius_(r) {} double area() const override { return 3.14159 * radius_ * radius_; } std::string name() const override { return "Circle"; } double radius() const { return radius_; } ​ private: double radius_; }; ​ class Rectangle : public Shape { public: Rectangle(double w, double h) : w_(w), h_(h) {} double area() const override { return w_ * h_; } std::string name() const override { return "Rectangle"; } double width() const { return w_; } double height() const { return h_; } ​ private: double w_, h_; }; ​ int main() { using namespace std; ​ Shape* shapes[] = { new Circle(5.0), new Rectangle(4.0, 6.0), new Circle(3.0) }; ​ cout << "===== dynamic_cast 指针版本 =====" << endl; for (auto s : shapes) { cout << s->name() << " 面积=" << s->area() << endl; ​ // 向下转型:成功返回有效指针,失败返回 nullptr if (Circle* c = dynamic_cast<Circle*>(s)) { cout << " 半径=" << c->radius() << endl; } else if (Rectangle* r = dynamic_cast<Rectangle*>(s)) { cout << " 宽=" << r->width() << " 高=" << r->height() << endl; } } ​ cout << "\n===== dynamic_cast 引用版本 =====" << endl; // 引用版本:失败时抛出 std::bad_cast try { Shape& s = *shapes[0]; // Circle Circle& c = dynamic_cast<Circle&>(s); // 成功 cout << "Circle半径:" << c.radius() << endl; ​ Shape& s2 = *shapes[1]; // Rectangle Circle& c2 = dynamic_cast<Circle&>(s2); // 失败!抛出 bad_cast } catch (const bad_cast& e) { cout << "bad_cast:" << e.what() << endl; } ​ for (auto s : shapes) delete s; return 0; }

19.2.2 typeid 运算符

// typeid_demo.cpp -- typeid运算符 #include <iostream> #include <typeinfo> #include <string> ​ class Base { public: virtual ~Base() {} virtual std::string type() const { return "Base"; } }; ​ class Derived : public Base { public: std::string type() const override { return "Derived"; } }; ​ int main() { using namespace std; ​ // ===== typeid 基本用法 ===== int i = 42; double d = 3.14; string s = "Hello"; ​ // typeid 返回 type_info 对象的引用 cout << "int: " << typeid(i).name() << endl; cout << "double: " << typeid(d).name() << endl; cout << "string: " << typeid(s).name() << endl; ​ // ===== typeid 与多态 ===== cout << "\n===== 多态类型 =====" << endl; Base b; Derived d2; Base* p1 = &b; Base* p2 = &d2; ​ // 对指针使用 typeid:返回指针类型(不是所指对象的类型) cout << "typeid(p1): " << typeid(p1).name() << endl; // Base* ​ // 对解引用指针使用 typeid:返回实际对象类型(动态类型) cout << "typeid(*p1): " << typeid(*p1).name() << endl; // Base cout << "typeid(*p2): " << typeid(*p2).name() << endl; // Derived ​ // ===== 类型比较 ===== cout << "\n===== 类型比较 =====" << endl; cout << boolalpha; cout << "p1指向Base:" << (typeid(*p1) == typeid(Base)) << endl; cout << "p2指向Derived:" << (typeid(*p2) == typeid(Derived)) << endl; cout << "p1和p2类型相同:" << (typeid(*p1) == typeid(*p2)) << endl; ​ // ===== 实际应用:类型安全的操作 ===== cout << "\n===== 类型安全操作 =====" << endl; Base* shapes[] = {new Base(), new Derived(), new Base()}; ​ for (auto s : shapes) { if (typeid(*s) == typeid(Derived)) cout << "这是Derived对象" << endl; else cout << "这是Base对象" << endl; delete s; } ​ return 0; }

19.3 枚举类型

// enum_types.cpp -- 枚举类型 #include <iostream> #include <string> ​ // ===== 传统枚举(不限定作用域)===== enum Color { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2 enum Status { ACTIVE, INACTIVE }; ​ // ⚠️ 传统枚举的问题: // 1. 枚举值泄漏到外层作用域 // 2. 不同枚举类型可以比较(隐式转换为int) // 3. 不能指定底层类型(默认int) ​ // ===== 限定作用域的枚举(C++11)===== enum class Direction { NORTH, SOUTH, EAST, WEST }; enum class Permission : uint8_t // 指定底层类型 { NONE = 0, READ = 1, WRITE = 2, EXECUTE = 4, ALL = READ | WRITE | EXECUTE }; ​ // ===== 枚举的前置声明(C++11)===== enum class Season : int; // 前置声明 void printSeason(Season s); ​ enum class Season : int { SPRING, SUMMER, AUTUMN, WINTER }; ​ void printSeason(Season s) { switch (s) { case Season::SPRING: std::cout << "春天" << std::endl; break; case Season::SUMMER: std::cout << "夏天" << std::endl; break; case Season::AUTUMN: std::cout << "秋天" << std::endl; break; case Season::WINTER: std::cout << "冬天" << std::endl; break; } } ​ int main() { using namespace std; ​ // 传统枚举 Color c = RED; int n = c; // ✅ 隐式转换为int // Color c2 = 0; // ❌ 不能从int转换 ​ // 不同枚举类型可以比较(危险!) // if (RED == ACTIVE) {} // 编译通过,但语义错误 ​ // 限定作用域枚举 Direction d = Direction::NORTH; // int m = d; // ❌ 不能隐式转换 int m = static_cast<int>(d); // ✅ 必须显式转换 ​ // 不同枚举类型不能比较 // if (Direction::NORTH == Season::SPRING) {} // ❌ 编译错误 ​ // 权限枚举 Permission perm = Permission::READ; cout << "READ = " << static_cast<int>(perm) << endl; ​ // 使用位运算(需要显式转换) auto combined = static_cast<Permission>( static_cast<uint8_t>(Permission::READ) | static_cast<uint8_t>(Permission::WRITE)); cout << "READ|WRITE = " << static_cast<int>(combined) << endl; ​ // 季节枚举 printSeason(Season::AUTUMN); ​ // 枚举的大小 cout << "\n枚举大小:" << endl; cout << "Color: " << sizeof(Color) << " 字节" << endl; cout << "Permission: " << sizeof(Permission) << " 字节" << endl; ​ return 0; }

19.4 类成员指针

// member_pointer.cpp -- 类成员指针 #include <iostream> #include <string> #include <vector> #include <algorithm> #include <functional> ​ class Screen { public: using Action = Screen& (Screen::*)(); // 成员函数指针类型别名 ​ Screen(int h, int w, char c) : height_(h), width_(w), contents_(h * w, c), cursor_(0) {} ​ // 成员函数 Screen& home() { cursor_ = 0; return *this; } Screen& end() { cursor_ = contents_.size() - 1; return *this; } Screen& forward() { if (cursor_ < contents_.size() - 1) ++cursor_; return *this; } Screen& back() { if (cursor_ > 0) --cursor_; return *this; } ​ char get() const { return contents_[cursor_]; } int pos() const { return cursor_; } ​ // 数据成员 int height_, width_; std::string contents_; int cursor_; }; ​ int main() { using namespace std; ​ Screen s(3, 5, 'X'); ​ // ===== 数据成员指针 ===== // 声明:类型 类名::*指针名 int Screen::*pHeight = &Screen::height_; int Screen::*pWidth = &Screen::width_; ​ // 通过对象使用成员指针 cout << "height = " << s.*pHeight << endl; // 3 cout << "width = " << s.*pWidth << endl; // 5 ​ // 通过指针使用成员指针 Screen* ps = &s; cout << "height = " << ps->*pHeight << endl; ​ // ===== 成员函数指针 ===== // 声明:返回类型 (类名::*指针名)(参数类型) Screen& (Screen::*pForward)() = &Screen::forward; Screen& (Screen::*pBack)() = &Screen::back; ​ // 通过对象调用 (s.*pForward)(); cout << "前进后位置:" << s.pos() << endl; ​ (s.*pBack)(); cout << "后退后位置:" << s.pos() << endl; ​ // 通过指针调用 (ps->*pForward)(); cout << "通过指针前进:" << s.pos() << endl; ​ // ===== 成员函数指针数组 ===== Screen::Action actions[] = { &Screen::home, &Screen::forward, &Screen::end, &Screen::back }; ​ // 执行所有动作 for (auto action : actions) (s.*action)(); ​ // ===== 使用 std::mem_fn 和 std::bind ===== cout << "\n===== mem_fn 和 bind =====" << endl; ​ // mem_fn:将成员函数包装为可调用对象 auto getPos = mem_fn(&Screen::pos); cout << "pos = " << getPos(s) << endl; ​ // bind:绑定成员函数 auto forward = bind(&Screen::forward, &s); forward(); cout << "bind forward后:" << s.pos() << endl; ​ return 0; }

19.5 嵌套类

// nested_class.cpp -- 嵌套类 #include <iostream> #include <string> #include <memory> ​ // 嵌套类:定义在另一个类内部的类 class TextQuery { public: // 嵌套类:QueryResult class QueryResult { friend class TextQuery; ​ public: QueryResult(const std::string& word, int count) : word_(word), count_(count) {} ​ void print() const { std::cout << "\"" << word_ << "\" 出现 " << count_ << " 次" << std::endl; } ​ int count() const { return count_; } ​ private: std::string word_; int count_; }; ​ // TextQuery 的成员 void addWord(const std::string& word) { wordCount_[word]++; } ​ QueryResult query(const std::string& word) const { auto it = wordCount_.find(word); int count = (it != wordCount_.end()) ? it->second : 0; return QueryResult(word, count); } ​ private: std::map<std::string, int> wordCount_; }; ​ // 在类外定义嵌套类的成员 // TextQuery::QueryResult::QueryResult(...) { ... } ​ int main() { using namespace std; ​ TextQuery tq; string text = "the quick brown fox jumps over the lazy dog the"; ​ // 分词并统计 istringstream iss(text); string word; while (iss >> word) tq.addWord(word); ​ // 查询 auto result1 = tq.query("the"); auto result2 = tq.query("fox"); auto result3 = tq.query("cat"); ​ result1.print(); // "the" 出现 3 次 result2.print(); // "fox" 出现 1 次 result3.print(); // "cat" 出现 0 次 ​ return 0; }

19.6 union:一种节省空间的类

// union_demo.cpp -- union #include <iostream> #include <string> #include <new> ​ // ===== 基本 union ===== union Data { int ival; double dval; char cval; }; // 大小等于最大成员的大小 ​ // ===== 匿名 union ===== struct Token { enum class TokenKind { INT, DOUBLE, STRING }; TokenKind kind; ​ union // 匿名union:成员直接在外层作用域可见 { int ival; double dval; // std::string sval; // ⚠️ 含有构造函数的类型需要特殊处理 }; }; ​ // ===== 含有类类型成员的 union ===== class MyUnion { public: enum class Type { INT, STRING, NONE }; ​ MyUnion() : type_(Type::NONE) {} ​ MyUnion(int v) : type_(Type::INT) { new (&ival_) int(v); // 定位new } ​ MyUnion(const std::string& s) : type_(Type::STRING) { new (&sval_) std::string(s); // 定位new } ​ MyUnion(const MyUnion& other) : type_(other.type_) { switch (type_) { case Type::INT: new (&ival_) int(other.ival_); break; case Type::STRING: new (&sval_) std::string(other.sval_); break; default: break; } } ​ ~MyUnion() { if (type_ == Type::STRING) sval_.~basic_string<char>(); // 手动析构 } ​ void show() const { switch (type_) { case Type::INT: std::cout << "int: " << ival_ << std::endl; break; case Type::STRING: std::cout << "string: " << sval_ << std::endl; break; default: std::cout << "none" << std::endl; } } ​ private: Type type_; union { int ival_; std::string sval_; }; }; ​ int main() { using namespace std; ​ // 基本 union Data d; d.ival = 42; cout << "ival = " << d.ival << endl; ​ d.dval = 3.14; // 覆盖了 ival cout << "dval = " << d.dval << endl; // d.ival 现在是未定义的 ​ cout << "union大小:" << sizeof(Data) << " 字节" << endl; ​ // 含类类型的 union MyUnion u1(42); MyUnion u2(string("Hello")); MyUnion u3; ​ u1.show(); u2.show(); u3.show(); ​ return 0; }

19.7 局部类

// local_class.cpp -- 局部类 #include <iostream> #include <string> #include <functional> // 局部类:定义在函数内部的类 std::function<int(int)> makeAdder(int n) { // 局部类 class Adder { public: Adder(int n) : n_(n) {} int operator()(int x) const { return x + n_; } private: int n_; // ⚠️ 局部类的限制: // 1. 不能定义静态数据成员 // 2. 不能访问外层函数的局部变量(除非是静态的) // 3. 可以访问外层函数的类型名、静态变量、枚举值 }; return Adder(n); } // 局部类在模板中的应用 template <typename T> std::function<bool(T)> makeGreaterThan(T threshold) { class Comparator { public: Comparator(T t) : threshold_(t) {} bool operator()(T val) const { return val > threshold_; } private: T threshold_; }; return Comparator(threshold); } int main() { using namespace std; auto add5 = makeAdder(5); auto add10 = makeAdder(10); cout << "add5(3) = " << add5(3) << endl; // 8 cout << "add10(3) = " << add10(3) << endl; // 13 auto gt5 = makeGreaterThan(5); auto gt10 = makeGreaterThan(10.0); cout << boolalpha; cout << "7 > 5: " << gt5(7) << endl; // true cout << "3 > 5: " << gt5(3) << endl; // false cout << "15.0 > 10.0: " << gt10(15.0) << endl; // true return 0; }

19.8 固有的不可移植的特性

19.8.1 位域

// bit_fields.cpp -- 位域 #include <iostream> // 位域:允许将多个标志位打包到一个整数中 struct NetworkPacket { unsigned int version : 4; // 4位:版本号(0-15) unsigned int type : 4; // 4位:类型(0-15) unsigned int flags : 8; // 8位:标志位 unsigned int length : 16; // 16位:长度(0-65535) // 总共 32 位 = 4 字节 }; struct Permissions { unsigned int read : 1; // 1位 unsigned int write : 1; // 1位 unsigned int execute : 1; // 1位 unsigned int : 5; // 5位填充(未命名) }; int main() { using namespace std; NetworkPacket pkt; pkt.version = 4; pkt.type = 2; pkt.flags = 0b00000001; pkt.length = 1024; cout << "版本:" << pkt.version << endl; cout << "类型:" << pkt.type << endl; cout << "标志:" << pkt.flags << endl; cout << "长度:" << pkt.length << endl; cout << "结构体大小:" << sizeof(NetworkPacket) << " 字节" << endl; Permissions perm = {1, 1, 0}; cout << "\n读权限:" << perm.read << endl; cout << "写权限:" << perm.write << endl; cout << "执行权限:" << perm.execute << endl; return 0; }

19.8.2 volatile 限定符

// volatile_demo.cpp -- volatile #include <iostream> // volatile:告诉编译器不要优化该变量 // 每次访问都从内存读取,不使用缓存 // 常见用途: // 1. 硬件寄存器 // 2. 多线程共享变量(但不能替代互斥锁) // 3. 信号处理程序中的变量 volatile int hardwareReg = 0; // 模拟硬件寄存器 // volatile 与 const 组合 volatile const int readOnlyReg = 0xFF; // 只读硬件寄存器 void readHardware() { // 每次都从内存读取,不会被优化为只读一次 for (int i = 0; i < 3; i++) std::cout << "寄存器值:" << hardwareReg << std::endl; } // volatile 成员函数 class HardwareDevice { public: void read() volatile { // 可以被 volatile 对象调用 std::cout << "读取设备" << std::endl; } void write() volatile { std::cout << "写入设备" << std::endl; } }; int main() { readHardware(); volatile HardwareDevice dev; dev.read(); dev.write(); return 0; }

19.8.3 链接指示(extern "C")

// extern_c.cpp -- 链接指示 #include <iostream> // extern "C":告诉编译器使用C语言的链接规则 // 主要用于与C代码互操作 // 单个函数 extern "C" void c_function(int x) { // 使用C链接,函数名不会被C++名字修饰 std::cout << "C函数:" << x << std::endl; } // 多个函数 extern "C" { void c_func1() { std::cout << "c_func1" << std::endl; } void c_func2() { std::cout << "c_func2" << std::endl; } int c_add(int a, int b) { return a + b; } } // 包含C头文件 // extern "C" // { // #include <stdio.h> // #include <string.h> // } // 在头文件中同时支持C和C++ #ifdef __cplusplus extern "C" { #endif void shared_function(int x) { std::cout << "共享函数:" << x << std::endl; } #ifdef __cplusplus } #endif int main() { c_function(42); c_func1(); c_func2(); std::cout << "c_add(3,4) = " << c_add(3, 4) << std::endl; shared_function(100); return 0; }

19.9 综合示例:内存池

// memory_pool.cpp -- 综合示例:内存池 #include <iostream> #include <vector> #include <string> #include <stdexcept> #include <new> #include <cstring> // 固定大小的内存池 template <typename T, size_t BlockSize = 64> class MemoryPool { private: // 内存块 struct Block { alignas(T) char data[sizeof(T)]; bool inUse = false; }; std::vector<Block> pool_; size_t allocated_ = 0; public: MemoryPool() : pool_(BlockSize) {} // 分配内存 T* allocate() { for (auto& block : pool_) { if (!block.inUse) { block.inUse = true; ++allocated_; return reinterpret_cast<T*>(block.data); } } throw std::bad_alloc(); } // 释放内存 void deallocate(T* p) noexcept { for (auto& block : pool_) { if (reinterpret_cast<T*>(block.data) == p) { block.inUse = false; --allocated_; return; } } } // 构造对象 template <typename... Args> T* construct(Args&&... args) { T* p = allocate(); try { new (p) T(std::forward<Args>(args)...); // 定位new } catch (...) { deallocate(p); throw; } return p; } // 析构并释放 void destroy(T* p) noexcept { p->~T(); deallocate(p); } size_t allocated() const { return allocated_; } size_t capacity() const { return pool_.size(); } size_t available() const { return capacity() - allocated(); } }; // 使用内存池的类 class Widget { public: Widget(const std::string& name, int val) : name_(name), val_(val) { std::cout << "[构造] " << name_ << "(" << val_ << ")" << std::endl; } ~Widget() { std::cout << "[析构] " << name_ << std::endl; } void show() const { std::cout << "Widget: " << name_ << " = " << val_ << std::endl; } private: std::string name_; int val_; }; int main() { using namespace std; MemoryPool<Widget, 5> pool; cout << "===== 内存池状态 =====" << endl; cout << "容量:" << pool.capacity() << endl; cout << "可用:" << pool.available() << endl; cout << "\n===== 分配对象 =====" << endl; Widget* w1 = pool.construct("Widget1", 100); Widget* w2 = pool.construct("Widget2", 200); Widget* w3 = pool.construct("Widget3", 300); cout << "已分配:" << pool.allocated() << endl; w1->show(); w2->show(); w3->show(); cout << "\n===== 释放对象 =====" << endl; pool.destroy(w2); cout << "释放w2后,已分配:" << pool.allocated() << endl; cout << "\n===== 复用内存 =====" << endl; Widget* w4 = pool.construct("Widget4", 400); // 复用w2的内存 w4->show(); cout << "\n===== 清理 =====" << endl; pool.destroy(w1); pool.destroy(w3); pool.destroy(w4); cout << "最终已分配:" << pool.allocated() << endl; return 0; }

📝 第19章知识点总结

知识点核心要点
重载 new/delete类级别重载,operator new分配内存,operator delete释放
定位 newnew (地址) 类型(参数),在指定内存构造,必须手动调用析构函数
dynamic_cast安全向下转型,指针版本失败返回nullptr,引用版本失败抛bad_cast
typeid返回type_info,对多态类型返回动态类型,对指针返回静态类型
enum class限定作用域,不隐式转换为int,可指定底层类型,推荐使用
数据成员指针类型 类名::*ptr = &类名::成员,通过.*->*使用
成员函数指针返回类型 (类名::*ptr)(参数),通过.*->*调用
mem_fn将成员函数包装为可调用对象
嵌套类定义在类内部,有自己的作用域,外层类不能直接访问嵌套类的私有成员
union所有成员共享内存,大小等于最大成员,含类类型成员需手动管理
局部类定义在函数内部,不能有静态数据成员,不能访问外层局部变量
位域指定成员占用的位数,节省内存,常用于硬件协议
volatile防止编译器优化,每次从内存读取,用于硬件寄存器和信号处理
extern "C"使用C链接规则,用于C/C++互操作,防止名字修饰
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 19:39:27

计算机小程序毕设实战-基于SSM的图书馆自习室座位预约小程序基于ssm+微信小程序的自习室预约小程序的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/15 20:23:45

Windows 10 下 Qt5.12 项目构建失败?可能是你的 Windows SDK 路径没配好

Windows 10下Qt5.12构建失败的深度排查与系统级修复指南当你满怀期待地在Windows 10上配置Qt5.12开发环境&#xff0c;却在构建项目时遭遇"shell32.lib无法打开"或"windows.h找不到"的错误提示&#xff0c;这种挫败感我深有体会。这不是简单的路径配置问题…

作者头像 李华
网站建设 2026/6/15 19:25:20

i.MX RT1170 CAAM模块实现ECDSA硬件签名与密钥保护实战

1. 项目概述与核心价值最近在做一个基于i.MX RT1170的物联网网关项目&#xff0c;安全需求非常明确&#xff1a;设备固件需要签名&#xff0c;关键通信指令也需要验签。一开始想用软件库实现ECDSA&#xff0c;但实测下来&#xff0c;在资源有限的MCU上做纯软件椭圆曲线运算&…

作者头像 李华
网站建设 2026/6/15 20:07:37

多维聚合实战:超越GROUP BY的数据操作核心方法

1. 项目概述&#xff1a;多维聚合中的数据操作&#xff0c;远不止GROUP BY那么简单“Part 20: Data Manipulation in Multi-Dimensional Aggregation”这个标题乍看像教科书里的章节编号&#xff0c;但如果你正在处理销售仪表盘、用户行为漏斗、IoT设备时序汇总&#xff0c;或是…

作者头像 李华