【C++】Cplusplus进阶

模板的进阶:

非类型模板参数

        是C++模板中允许使用具体值(而非类型)作为模板参数的特性。它们必须是编译时常量,且类型仅限于整型、枚举、指针、引用。(char也行)

        STL标准库里面也使用了非类型的模板参数。

// 非类型模板参数示例:固定大小的数组
template <typename T, int Size>
class FixedArray 
{
private:T data[Size];
public:T& operator[](int index) {return data[index];}constexpr int getSize() const { return Size; }
};int main() {FixedArray<int, 5> arr;  // Size=5在编译时确定arr[2] = 42;static_assert(arr.getSize() == 5);
}

        在 C++ 标准中,非类型模板参数不能直接使用 std::string,但可以使用字符数组或字符指针的形式间接实现类似效果。

template<const char* str>
struct MyTemplate { /* ... */ };// 定义外部链接的字符数组(C++17 起可用)
extern const char my_str[] = "Hello";
MyTemplate<my_str> obj; // 合法

模板特化

        是C++中针对特定类型或条件提供定制化模板实现的技术,就是模板的特殊化处理,特化不能单独存在。它分为全特化和偏特化,两种形式。

        这里最后一次比较,其实变成了指针与指针比较,比较的是地址的大小。那么这里如果要让指针里面的数据进行比较,那么就要用到模板的特化。

template<class T>
bool Greater(T left, T right)
{return left > right;
}template<>
bool Greater<Date*>(Date* left,Date* right)
{return *left > *right;
}

        这样走Date* 比较的时候,就会走第二个模板函数。

        除了函数能特化,类也可以特化。

template<class T>
struct Less
{bool operator()(const T& x1,const T& x2) const{return x1 < x2;}
};template<>
struct Less<Date*>
{bool operator()(Date* x1,Date * x2) const {return *x1 < *x2;}
};

        上面仿函数也可以使用class,但是要注意在public下面操作,不然调不到函数。

        

        这里使用STL库里面的优先级队列,用自己写的模板特化,发现也是可以使用的。

偏特化

        允许为模板参数的一部分或特定条件提供特殊实现。它适用于类模板,但不支持函数模板。

// 通用模板
template <class T, class U>
class MyClass 
{
public:void print() {  cout << "General template\n"; }
};// 偏特化:当第二个参数为 int 时
template <class T>
class MyClass<T, int> 
{
public:void print() { cout << "Partial specialization (U = int)\n"; }
};// 偏特化:当两个参数均为指针类型时
template <class T, class U>
class MyClass<T*, U*> 
{
public:void print() { cout << "Partial specialization (both pointers)\n"; }
};// 使用示例
int main() 
{MyClass<double, char> a;      // 通用模板MyClass<float, int> b;        // 偏特化(U = int)MyClass<int*, double*> c;     // 偏特化(指针类型)a.print();  // 输出: General templateb.print();  // 输出: Partial specialization (U = int)c.print();  // 输出: Partial specialization (both pointers)
}
template <class T, class U>
class MyClass<T&, U&> 
{
public:void print() { cout << " T& , U& \n"; }
};

模板不支持分离编译

        声明(.h),定义(.cpp)分离。

 PS:模板在同一文件下可以类外定义。

        在类模板中使用typename关键字加在内嵌类型(iterator)前是为了告诉编译器该名称是一个类型,而非静态成员或变量这种情况发生在模板参数未实例化时,当访问嵌套的依赖类型时,必须使用typename消除歧义

        zs : : vector<T> : : iterator ,这里要加 typename 。不然编译器区分不清楚这里是类型还是变量。因为静态函数、变量也可以指定类域就可以访问。

        

        这里把push_back() 分开定义后,使用出现链接错误。

        因为构造函数、size()函数、operator[ ],在vector.h中有定义,所以vector 实例化 v 的时候,这些成员函数同时实例化,直接就有定义。编译阶段直接确定地址。

        而 push_back()、insert()在 vector.h 中只有声明,没有定义。那么只有在链接阶段去确认地址。    

        但是这里 vector.cpp 中模板类型的 T 无法确定,所以没有实例化,就无法进入符号表。进入不了符号表后面链接阶段就会发生错误。

根本原理:

C++标准规定模板是编译期多态机制,编译器需要根据调用处的具体类型生成代码。若模板实现不可见(如分离到.cpp文件),则无法完成实例化。

解决方案:

1.模板声明和定义不要分离到 .h 和 .cpp (推荐)。

2.在cpp 显示实例化。(不推荐,换个类型就要实例化一次,麻烦)

模板总结:

一、优点:

  1. 类型安全:模板在编译期进行类型检查,比宏更安全(如std::vector<int>只能存储int类型)
  2. 代码重用:通过泛型编程减少重复代码(如一个max()模板可处理int/double/string等类型)
  3. 零运行时开销:模板实例化在编译期完成,无额外运行时成本
  4. 高性能泛型算法:STL算法(如sort)能针对不同类型生成优化代码

二、缺点:

  1. 编译错误晦涩:类型不匹配时错误信息冗长(如缺少某个成员函数的错误可能长达数十行)
  2. 编译时间膨胀:每个模板实例化都会生成新代码,大型项目编译时间显著增加
  3. 代码膨胀风险:多个类型实例化可能导致二进制文件增大(如vector<int>和vector<string>会生成两份代码)
  4. 调试困难:调试器难以跟踪模板实例化代码

C++的继承:

        C++继承是面向对象编程的核心机制之一,允许派生类复用基类的属性和方法,同时扩展或修改其行为。

        一个学校里面,人有很多种身份,比如学生、老师、校长、保洁工作人员等。他们有共同的特点也有不同的地方。那么如果对每个人单独的来写一份代码以表明其全部特征,那么代码会非常的冗余。

        因为其作为人这个个体在很多的特征上是相似的,那么使用C++的继承就可以很好的解决这方面的问题。

// 基类:个人
class Person 
{
public:string name;int age;string gender;void display() const {cout << "姓名: " << name << "\n年龄: " << age<< "\n性别: " << gender << endl;}
};// 学生类
class Student : public Person 
{
private:string studentID;
};// 教师类
class Teacher : public Person {
private:string employeeID;
};

        继承允许一个类(派生类,student,teacher )基于另一个类(基类,Person )来创建,从而获得基类的属性和方法,同时可以添加新的特性或覆盖已有的方法。 

        基本语法,派生类通过冒号后跟访问说明符(如public、protected、private)和基类名称来继承基类。

        

        派生类既有基类的属性 (name、age、 gender),也有自己拓展的属性( studentID、employeeID )。

代码复用:继承允许派生类直接使用基类的成员(变量和函数),避免重复编写相同逻辑。

层次化建模:通过继承表达现实世界的分类关系(如"动物→哺乳动物→狗"),使代码结构更符合逻辑认知。

继承方式:

        public、protected和private继承。public继承是最常用的,它保持基类成员的访问权限不变。protected继承会将基类的public和protected成员变为派生类的protected成员。private继承则将所有基类成员变为派生类的private成员。这些不同继承方式会影响派生类及其后续派生类对基类成员的访问权限。

        

        其实有规律,直接由权限更小的那个控制。实际上就只有public继承用的比较多。

        protected\priveate:类外不能访问,类里面可以访问。

        不可见:隐身,类里面外面都无法访问。

私有成员的意义:不想被子类继承的成员。

基类中想给子类复用,但是又不想暴露直接访问的成员,就应该定义成保护


class Parent 
{
public:string name = "Parent";
};class Child : public Parent 
{
public:string name = "Child";  // 隐藏父类的namevoid printNames() {cout << "子类 name: " << name << endl;           // 输出 Childcout << "父类 name: " << Parent::name << endl;   // 输出 Parent}
};int main() 
{Child obj;obj.printNames();return 0;
}

 

        当子类和父类都定义了同名成员变量name时,子类会隐藏父类的同名成员。若需访问父类成员,需通过作用域解析运算符显式指明

1.在继承体系中基类和派生类都有独立的作用域。

2.子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员  显示访问)

         实际上的内存存储中,子类对象包含了基类的数据(name)。.

        若父类的nameprivate

        此时子类定义的name是独立的新成员,不会产生命名冲突(但父类成员仍然存在,只是不可直接访问)。

class A
{
public:void func(){cout << "fucn()" << endl;}
};class B : public A
{
public:void func(int i){cout << "func(int i)->" << endl;}
};

        

        有的地方就会提问这里两个 func() 是不是构造函数重载?因为这里是两个不同的类域,所以其构成隐藏。

        当子类对象赋值给父类对象时,会发生对象切片(切割)。这个过程会自动截断子类特有的成员,只保留父类部分

        子类对象可以赋值给父类对象/指针/引用。这里虽然是不同类型,但是不是隐式类型转换。赋值兼容转换,第三个就能看出来,这里是个特殊支持,语法天然支持。

        子类切割对象赋值给父类,但是不能把父类对象反向赋值给子类对象

        指针或者引用,其指向父类那一部分的地址或者是那一部分的别名。


继承关系中的默认函数表现:

子类编译器默认生成的 构造函数

        1、自己的成员,跟类和对象一样。内置类型不处理,自定义类型调用它自己的默认构造。
        2、继承父类成员,必须调用父类的构造函数初始化。

class Person
{
public:string _name;string _sex;int _age;Person(const char* name):_name(name),_sex("男"),_age(10){cout << "Person()" << endl;}
};// 学生类
class Student : public Person
{
public:int _num;Student(const char* name, int num):Person(name)  /*显式调用父类构造函数*/ , _num(num){cout << "Studet()" << endl;}};int main() 
{Student s1("张三",001);return 0;
}

        注意上面子类再初始化列表里,调用父类的构造函数,初始化继承成员。

子类编译器生成默认生成的 拷贝构造

1、自己成员,跟类和对象一样。内置类型值拷贝,自定义类型调用它的拷贝构造。
2、继承的父类成员,必须调用父类拷贝构造初始化。

 Person(const Person& p):_name(p._name),_sex(p._sex),_age(p._age){cout << "Person(const Person& )" << endl;}Student(const Student& s):Person(s)    /*子类成员拷贝*/,_num(s._num){cout << "Studet(const Student& )" << endl;}int main() 
{Student s1("张三",001);Student st2(s1);return 0;
}

 

        这里子类拷贝构造函数(Student(const Student& s))初始化列表位置,传入基类拷贝构造函数(Person(const Person& p) )的参数,直接使用了子类对象(s)。这里其实是前面切片的应用。

子类编译器默认生成的 赋值运算符

1、自己成员,跟类和对象一样。内置类型值拷贝,自定义类型调用它 operator= 的。
2、继承的父类成员,必须调用父类的 operator= 

Person& operator=(const Person& p)
{cout << "Person& operator=(const Person& )" << endl;_name = p._name;_sex = p._sex;_age = p._age;return *this;
}Student& operator=(const Student& s)
{if (this != &s){Person::operator=(s);   // 调用父类赋值_num = s._num;}cout << "Student& operator=(const Student& )" << endl;return *this;
}int main() 
{Student s1("张三",001);Student st2(s1);Student st3("李四",002);st2 = st3;return 0;
}

 

        这里有个注意的点,调用父类的赋值运算符时要使用类域指定,如果不指定类域,子类默认会去调用自己的赋值运算符,构成死循环。

子类编译器默认生成的 析构函数

1、自己的成员内置类型不处理,自定义类型调用它的析构函数。
2、继承父类的成员,调用父类析构函数处理。

 ~Person()
{cout << "~Person" << endl;
}~Student()
{Person::~Person();cout << "~Student() " << endl;//...
}

       子类的析构函数跟父类的析构函数构成隐藏。直接调用调不到,要指定类域。  

        

        这里会发现Peson的构造函数调用了三次但是,析构函数调用了六次。这里其实是因为析构函数很特殊。不需要去显示的掉用基类的析构函数,编译器会自己自动的去调用

~Student()
{//Person::~Person();    //不用显示调用cout << "~Student() " << endl;//...
}

        这是因为其数据存储结构,比如一个子类 (Student),它会先存储父类(Person)的成员,然后在下面存储自己的成员。因为其数据存在栈帧上的,要遵循后进先出规则,所以后构造的先析构(与构造顺序相反,子类数据后构造),先调用派生类的析构函数,再调用基类的析构函数。

        每个子类析构函数后面会自动调用父类析构函数,这样才能保证先析构子类,再析构父类。(自己手写编译器无法保证顺序)

继承和友元:

        PS:友元关系不能被继承。基类的友元不会自动成为派生类的友元。

        如果想访问子类的私有数据,设置为子类的友元就行。

继承中静态成员的作用与访问规则

        静态成员(静态变量、静态方法)属于类本身,而非类的实例。所有实例共享静态成员,且通过类名直接访问。

class Person
{
public:Person() { ++_count; }string _name;static int _count;    //静态成员变量
};int Person::_count = 0;class Student : public Person
{
protected:int _num;
};

        共享性:父类的静态成员会被子类继承,但子类与父类共享同一份静态成员。

class Parent 
{ 
public:
static int value; 
};class Child : public Parent 
{ 
public: 
static int value; 
};Parent::value = 10;  // 父类静态成员
Child::value = 20;   // 子类静态成员(隐藏父类的同名成员)

        隐藏:若子类定义了同名静态成员,父类的静态成员会被隐藏,但未被覆盖(通过父类名仍可访问)。

多继承:

单继承:单继承指一个子类仅能继承一个父类的属性和方法。这是大多数面向对象编程语言的基础特性,能简化代码结构并减少复杂性。

class Animal {
public:void eat() { cout << "Eating" << endl; }
};class Dog : public Animal {
public:void bark() { cout << "Barking" << endl; }
};

多继承:多继承允许一个子类同时继承多个父类,增强了代码复用能力,但可能引发命名冲突(如多个父类有同名成员)和复杂性。

class Base1 { public: int a = 100; };
class Base2 { public: int b = 200; };class Derived : public Base1, public Base2 
{
public:int sum() { return a + b; }
};

Q:如何定义一个不能被继承的类?

1.父类构造私有化。子类对象实例化不能调用构造函数。

2. final 关键字 修饰 不能被继承的类。 (C++11)

Q:下面代码 p1、p2、p3的大小关系?

class Base1 { public: int _a; };
class Base2 { public: int _b; };class Derived : public Base1, public Base2
{
public:int _d;
};int main()
{Derived d;Base1* p1 = &d;Base2* p2 = &d;Derived* p3 = &d;return 0;
}

A:p1=p3!=p2

        这里其实是看对切割的理解深不深。

        这里p1指向的是base1,p2指向的是base2,都是指向对应数据的开头。p3指向的是整体,指向的是整体数据的首地址。

class Derived : public Base2, public Base1  //先继承 Base2
{
public:int _d;
};

PS:子类先继承谁,谁的数据在前面(Base2)。

        这里数据位置改变,p1、p2指向的位置也会改变。p2=p3!=p1。

Q:这里p1、p2谁的地址大(先继承Base1,再继承Base2)?

        因为数据存储在栈帧中,是先存低地址再存高地址(这里先存的_a、_b、_c)。所以 p2 > p1、p3。

        

         

菱形继承:

        菱形继承是多继承的特殊情况,指一个子类的多个父类继承自同一个基类,导致基类的成员在子类中存在多份副本。

class Person
{
public:string _name;
};class Student : public Person
{
protected:int _num;
};class Teacher :public Person
{};class Assistant :public Student, public Teacher
{};

        当多个父类继承自同一个祖先类时,可能导致成员重复和调用歧义。菱形继承有数据冗余和二义性的问题。在 Assistant 的对象中 Person 成员会有两份。

        指定类域调用就明确了。监视窗口能看到有多份的数据。

菱形虚拟继承:

        通过虚拟继承virtual关键字),中间派生类(B和C)共享同一份基类A的实例,从而消除冗余和二义性。

class A 
{ 
public: int _a; 
};class B : virtual public A  // 虚继承
{ 
public: int _b; 
};  class C : virtual public A  // 虚继承
{ 
public: int _c; 
};  class D : public B, public C 
{ 
public: int _d;
};
内存示意图:

        没有进行虚继承的情况:

        数据顺序排布,这里先继承的B,所以B的成员数据在A的前面。D对象里面存储了多个父类的成员数据( _a )。

       虚继承的情况:

        A 的成员数据在公共区域且只存储了一份,红杠上的地址存储了一个偏移量,是离 A 的距离 ,用于对象B、C 查找到 A 的位置。(注意这里编译器使用的X32位编译的,方便查看)

        这时候发生切片(切割)的时候就跟前面有些不一样了。这里B对象(b)由两个部分组成,一个是B自己,还有一个是A的数据。 

        A 在公共数据区域,切片后怎么去找这里的 A 呢(pb->_a)?这里直接指针加偏移量就是_a,同理 pc->_c 也是一样的。

PS:这里偏移量是16进制,14是20,0C是12。

D对象内存布局:
+----------------+
| B的虚基表指针  |
+----------------+
| C的虚基表指针  |
+----------------+
| A::data        |  // 唯一副本
+----------------+

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/76564.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于pycharm远程连接服务器如何debug

1、pycharm远程连接只有pycharm专业版才可以&#xff0c;在校学生可以用学校邮箱申请。另外&#xff0c;网上电商也可以&#x1f92b; 2、远程连接有很多教程&#xff0c;可以参考的文章有很多。这里主要记录关于远程连接服务器debug遇到的一些问题。 3、由于远程连接服务器开…

数据结构每日一题day11(链表)★★★★★

题目描述&#xff1a;有一个带头结点的单链表L&#xff0c;请设计一个算法查找其第1个数据值为e的结点&#xff0c;若存在则返回指向该结点的指针&#xff0c;若不存在则返回 NULL。 算法思想&#xff1a; 输入检查&#xff1a;若链表为空&#xff08;仅有头结点&#xff09;&…

《HarmonyOS Next开发进阶:打造功能完备的Todo应用华章》

章节 6&#xff1a;日期选择器与日期处理 目标 学习如何使用DatePicker组件。理解日期格式化和日期计算。 内容 日期选择器基础 使用DatePicker组件。处理日期选择事件。 日期格式化 格式化日期为友好的文本。 日期计算 判断日期是否过期或即将到期。 代码示例 Entry Com…

迅饶科技X2Modbus网关-GetUser信息泄露漏洞

免责声明&#xff1a;本号提供的网络安全信息仅供参考&#xff0c;不构成专业建议。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权&#xff0c;请及时与我联系&#xff0c;我将尽快处理并删除相关内容。 漏洞描述 该漏洞的存在是由于GetUser接口在…

Go 原理剖析:数据结构之字符串

在 Go 语言中&#xff0c;字符串&#xff08;string&#xff09;是一个非常重要的数据类型。它看似简单&#xff0c;但背后却隐藏着不少有趣的原理和优化技巧。今天我们就来聊聊 Go 中字符串的底层结构、特性&#xff0c;以及如何高效地使用它。 1. 字符串的底层结构 字符串的…

【SPP】蓝牙链路控制(LC)在SPP中互操作性深度解析

在蓝牙协议栈的精密分层体系中&#xff0c;其链路控制&#xff08;Link Control, LC&#xff09;层作为基带层的核心组件&#xff0c;承载着物理信道管理、连接建立与维护等关键任务。其互操作性要求直接决定了不同厂商设备能否实现无缝通信。本文将以蓝牙技术规范中的LC互操作…

Windows C++ 排查死锁

开发出来应用程序突然间卡死不动&#xff0c;如果其中是因为死锁问题卡列该如何排查 下面是一个简单的死锁例子 #include <iostream> #include <thread> #include <mutex>std::mutex a, b;void function_a() {std::lock_guard<std::mutex> _x(a);std:…

【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…

【易订货-注册/登录安全分析报告】

前言 由于网站注册入口容易被机器执行自动化程序攻击&#xff0c;存在如下风险&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露&#xff0c;不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 &#xff0c;造成用户无法登陆、注册&#xff0c;大量收到垃圾短信的…

GLPI 未授权SQL注入漏洞(CVE-2025-24799)

免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…

基于Deepface的情绪识别c++

基于Deepface的情绪识别c 文章目录 基于Deepface的情绪识别c简介下载模型并转为onnx&#xff08;facial_expression_model_weights.h5&#xff09;测试取出照片的人脸部分并处理成模型输入格式用模型推理一下看看结果 用onnxruntime的c库推理 简介 DeepFace是一个基于深度学习…

Java的数据库编程——JDBC基础

JDBC编程 一、概述1.1 概念介绍1.2 驱动包下载1.3 导入驱动包 二、通过Java程序操作数据库2.1 通过 JDBC 进行 插入数据 操作2.1.1 创建“数据源(DataSource)——描述要操作的数据库、数据是在哪”2.1.2 与服务器建立连接2.1.3 构造sql语句&#xff0c;并且对字符串类型的sql进…

DeepSeek-R1 面试题汇总

Deepseek-r1 面试宝典 原文地址&#xff1a;https://articles.zsxq.com/id_91kirfu15qxw.html DeepSeek-R1 面试题汇总 DeepSeek-R1 面试题汇总 GRPO&#xff08;Group Relative Policy Optimization&#xff09;常见面试题汇总篇 DeepSeek-R1 DeepSeek-R1-Zero 常见面试题汇总…

SSL/TLS

http ssl传输层 -> https 安全套接层 SSL/TLS 1、核心角色与文件2、证书生成流程2.1、生成CA根证书2.2、生成服务端证书2.3 生成客户端证书&#xff08;双向认证&#xff09; 3、SSL/TLS 认证模式3.1、单向认证&#xff08;默认 HTTPS&#xff09;3.2、双向认证&#xff0…

HTML 音频(Audio)学习笔记

一、HTML 音频概述 在 HTML 中&#xff0c;音频可以通过多种方式播放&#xff0c;但要确保音频在不同浏览器和设备上都能正常播放&#xff0c;需要掌握一些技巧。HTML5 引入了 <audio> 元素&#xff0c;为音频播放提供了一种标准方法&#xff0c;但在 HTML4 中&#xff…

php开发rest api,哪个框架最好

在 2025 年&#xff0c;选择适合开发 REST API 的 PHP 框架需要根据项目需求、性能要求和团队技术栈进行权衡。以下是一些推荐的 PHP 框架及其适用场景&#xff1a; 1. Laravel 特点&#xff1a;功能丰富&#xff0c;生态系统强大&#xff0c;内置 API 资源&#xff0c;支持 …

前端入门之CSS

CSS: HTML负责定义页面结构;JS负责处理页面逻辑和点击事件;CSS负责用于描述 HTML 元素的显示方式,通过 CSS 可以控制颜色、字体、布局等。 核心语法: 选择器: 类选择器主要用于选中需要添加样式的 HTML 元素。主要分为:类选择器(.class-name { ... })、标签选择器(…

MCP协议的Streamable HTTP:革新数据传输的未来

引言 在数字化时代&#xff0c;数据传输的效率和稳定性是推动技术进步的关键。MCP&#xff08;Model Context Protocol&#xff09;作为AI生态系统中的重要一环&#xff0c;通过引入Streamable HTTP传输机制&#xff0c;为数据交互带来了革命性的变化。本文将深入解读MCP协议的…

MySQL - 索引原理与优化:深入解析B+Tree与高效查询策略

文章目录 引言一、BTree索引核心原理1.1 索引数据结构演化1.2 BTree的存储结构通过主键查询&#xff08;主键索引&#xff09;商品数据的过程通过非主键&#xff08;辅助索引&#xff09;查询商品数据的过程 MySQL InnoDB 的索引原理 二、执行计划深度解析三、索引失效的六大陷…

《K230 从熟悉到...》识别机器码(AprilTag)

《K230 从熟悉到...》识别机器码&#xff08;aprirltag&#xff09; tag id 《庐山派 K230 从熟悉到...》 识别机器码&#xff08;AprilTag&#xff09; AprilTag是一种基于二维码的视觉标记系统&#xff0c;最早是由麻省理工学院&#xff08;MIT&#xff09;在2008年开发的。A…