【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.pswp.cn/diannao/76564.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76564.shtml
英文地址,請注明出處:http://en.pswp.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…