【C++】特殊類的設計、單例模式以及Cpp類型轉換

📚?博主的專欄

🐧?Linux???|?? 🖥??C++???|?? 📊?數據結構??|?💡C++ 算法?| 🌐?C 語言

上篇文章: C++ 智能指針使用,以及shared_ptr編寫

下篇文章: C++ IO流

目錄

特殊類的設計

請設計一個類,不能被拷貝

請設計一個類,只能在堆上創建對象

請設計一個類,只能在棧上創建對象

請設計一個類,不能被繼承

請設計一個類,只能創建一個對象(單例模式)

設計模式:

單例模式:

餓漢模式

懶漢模式

C++的類型轉換

C語言中的類型轉換

CPP中類型轉換

為什么C++需要四種類型轉換

隱式類型轉換

示例:內置類型 -> 自定義類型

示例:自定義類型 -> 內置類型

自定義類型和自定義類型之間的轉換

隱式類型轉換的坑:

C++強制類型轉換

static_cast(對應之前的隱式類型轉換)

reinterpret_cast(對應的之前的顯式類型轉換)

const_cast

dynamic_cast(專門爭對C++設計的,向下轉換)

RTTI(了解)運行時類型識別


特殊類的設計

請設計一個類,不能被拷貝

拷貝只會放生在兩個場景中:拷貝構造函數以及賦值運算符重載,因此想要讓一個類禁止拷貝,只需讓該類不能調用拷貝構造函數以及賦值運算符重載即可。

線程不能被拷貝,IO流(IO流中的緩沖區不拷貝)不能被拷貝

C++98:

將拷貝構造函數與賦值運算符重載只聲明不定義,并且將其訪問權限設置為私有即可。

C++11:

請設計一個類,只能在堆上創建對象

實現方式:

1. 將類的構造函數私有,拷貝構造聲明成私有。防止別人調用拷貝在棧上生成對象。

2. 提供一個靜態的成員函數,在該靜態成員函數中完成堆對象的創建

class HeapOnly
{
public:static HeapOnly* CreateObject(){return new HeapOnly;//智能在堆上new}
private:HeapOnly() {}// C++98// 1.只聲明,不實現。因為實現可能會很麻煩,而你本身不需要// 2.聲明成私有HeapOnly(const HeapOnly&);// or
// C++11HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly&) = delete;};

調用成員函數需要對象,因此將函數指定為static讓其只屬于類,不屬于對象?

	//調用成員函數需要對象,因此將函數指定為static讓其只屬于類,不屬于對象HeapOnly* obj4 = HeapOnly::CreateObject();

第一種辦法:

為了防止調用拷貝構造,因此將拷貝構造也設置為私有,或者使用C++11的方法,直接封掉拷貝構造

	HeapOnly obj5(*obj4);

一般封了拷貝構造,將賦值也封上,避免發生淺拷貝。

第二種方法:

將析構私有化(讓析構無法自動調用):再自己寫函數顯示調用自己寫的釋放指針函數:

class HeapOnly
{
public:void Release(){delete this;}
private:~HeapOnly(){ }
};

請設計一個類,只能在棧上創建對象

同上將構造函數私有化,然后設計靜態方法創建對象返回即可

class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}// 禁掉operator new可以把下面用new 調用拷貝構造申請對象給禁掉// StackOnly obj = StackOnly::CreateObj();// StackOnly* ptr3 = new StackOnly(obj);void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly():_a(0){}
private:int _a;
};

請設計一個類,不能被繼承

C++98方式

// C++98中構造函數私有化,派生類中調不到基類的構造函數。則無法繼承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};

C++11方法

final關鍵字,final修飾類,表示該類不能被繼承。

class A final
{// ....
};

請設計一個類,只能創建一個對象(單例模式)

設計模式:

設計模式(Design Pattern)是一套被反復使用、多數人知曉的、經過分類的、代碼設計經驗的總結。為什么會產生設計模式這樣的東西呢?就像人類歷史發展會產生兵法。最開始部落之間打仗時都是人拼人的對砍。后來春秋戰國時期,七國之間經常打仗,就發現打仗也是有套路的,后來孫子就總結出了《孫子兵法》。孫子兵法也是類似。

使用設計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設計模式使代碼編寫真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。

設計模式舉例:

單例模式

迭代器模式

適配器模式

觀察者

工廠?

單例模式:

一個類只能創建一個對象,即單例(單實例)模式,該模式可以保證系統中該類只有一個實例,并提供一個訪問它的全局訪問點,該實例被所有程序模塊共享。比如在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數據由一個單例對象統一讀取,然后服務進程中的其他對象再通過這個單例對象獲取這些配置信息,這種方式簡化了在復雜環境下的配置管理。

單例模式有兩種實現模式:

餓漢模式

就是說不管你將來用不用,程序啟動時就創建一個唯一的實例對象。

優點:簡單

缺點:可能會導致進程啟動慢,且如果有多個單例類對象實例啟動順序不確定。

餓漢(很饑餓,極早就創建對象)模式 : 一開始就(main函數之前)就創建對象
問題1:很多單例類,都是餓漢模式,有些單例對象初始化資源很多,導致程序啟動慢,遲遲進不了main函數
問題2:如果兩個單例類有初始化依賴關系,餓漢也無法解決。比如A類和B類是單例,A單例要連接數據庫,B單例要用A單例訪問數據庫。

示例代碼:

 //餓漢(很饑餓,極早就創建對象)模式 : 一開始就(main函數之前)就創建對象//問題1:很多單例類,都是餓漢模式,有些單例對象初始化資源很多,導致程序啟動慢,遲遲進不了main函數//如果兩個單例類有初始化依賴關系,餓漢也無法解決。比如A類和B類是單例,A單例要連接數據庫,B單例要用A單例訪問數據庫
class ConfigInfo
{
public:static ConfigInfo* GetInstance(){return &_sInfo;//可以用指針也能用引用(看需求)}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化構造函數ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷貝構造和賦值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存網絡ipint _port = 80;//端口//...// 聲明 static ConfigInfo _sInfo;//受類域的限制,但實際上在靜態區,這里只是一個聲明,需要在類外面定義
};// 定義
ConfigInfo ConfigInfo::_sInfo;
int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

如果這個單例對象在多線程高并發環境下頻繁使用,性能要求較高,那么顯然使用餓漢模式來避免資源競爭,提高響應速度更好
?

懶漢模式

優點:第一次使用實例對象時,創建對象。進程啟動無負載。多個單例實例啟動順序自由控制。

如果單例對象構造十分耗時或者占用很多資源,比如加載插件啊, 初始化網絡連接啊,讀取文件啊等等,而有可能該對象程序運行時不會用到,那么也要在程序一開始就進行初始化,就會導致程序啟動時非常的緩慢。 所以這種情況使用懶漢模式(延遲加載)更好。

懶漢就是第一次調用時,創建單例對象

//懶漢完美解決上面餓漢存在的問題
class ConfigInfo
{
public:static ConfigInfo* GetInstance(){static ConfigInfo info;//定義一個局部的靜態對象return &info;}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化構造函數ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷貝構造和賦值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存網絡ipint _port = 80;//端口//...
};int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

缺點是:在C++11前,局部static對象構造,有線程安全的風險

C++11之前的解決辦法:仍然在第一次調用的時候再創建

class ConfigInfo
{
public:static ConfigInfo* GetInstance(){if (_spInfo == nullptr){_spInfo = new ConfigInfo;}return _spInfo;}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化構造函數ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷貝構造和賦值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存網絡ipint _port = 80;//端口//...// 定義一個靜態指針static ConfigInfo* _spInfo;//受類域的限制,但實際上在靜態區,這里只是一個聲明,需要在類外面定義
};ConfigInfo* ConfigInfo::_spInfo = nullptr;
int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

現在還不能避免多線程調用的線程安全的問題:

如果兩個線程都來,t1先來正在new的時候,t2判斷了_spInfo為空,也要開始new,t1已經new完了,賦值給了_spInfo,最怕的是,t2時間片到了,開始在判斷后的地方休眠,t1繼續執行,并且已經SetIp(),t2醒了,又開始new,將t1申請的全給覆蓋,導致內存泄漏。因此需要加鎖?。

注意靜態成員函數,只能訪問靜態的成員變量,因此mutex的對象也要設置成靜態的:

注意看注釋

class ConfigInfo
{
public:static ConfigInfo* GetInstance(){//加鎖t1、t2只能一個進判斷,保證只會new一個對象//單單只這樣寫,會導致,已經創建好對象了,但是每次調用GetInstance的時候都需要再被加鎖/*	unique_lock<mutex> lock(_mtx);if (_spInfo == nullptr){_spInfo = new ConfigInfo;}*///因為不能直接將鎖加載if判斷內,這仍然會導致線程安全,要的就是,每個線程都得判斷對象是否創建//解決辦法:多寫一層if (_spInfo == nullptr){unique_lock<mutex> lock(_mtx);if (_spInfo == nullptr){_spInfo = new ConfigInfo;}}return _spInfo;}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化構造函數ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷貝構造和賦值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存網絡ipint _port = 80;//端口//...// 定義一個靜態指針static ConfigInfo* _spInfo;//受類域的限制,但實際上在靜態區,這里只是一個聲明,需要在類外面定義static mutex _mtx;
};ConfigInfo* ConfigInfo::_spInfo = nullptr;
mutex ConfigInfo::_mtx;
int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}

C++的類型轉換

C語言中的類型轉換

在C語言中,如果賦值運算符左右兩側類型不同,或者形參與實參類型不匹配,或者返回值類型與接收返回值類型不一致時,就需要發生類型轉化,C語言中總共有兩種形式的類型轉換:隱式類型轉換和顯式類型轉換。

1. 隱式類型轉化:編譯器在編譯階段自動進行,能轉就轉,不能轉就編譯失敗

2. 顯式類型轉化:需要用戶自己處理

隱式類型轉換一般是類型關聯度緊密(像是指針和double不能轉換的就能轉,整形、浮點型、char(ASCII碼)之間就能互相隱式類型轉。

顯式(強制)類型轉換一般就是任意指針之間,整形(數據大小)和指針(字節編號)之間

示例:

	// 隱式類型轉換double d = i;printf("%d, %.2f\n", i, d);int* p = &i;// 顯示的強制類型轉換int address = (int)p;printf("%p, %d\n", p, address);

缺陷:

轉換的可視性比較差,所有的轉換形式都是以一種相同形式書寫,難以跟蹤錯誤的轉換

CPP中類型轉換

為什么C++需要四種類型轉換

C風格的轉換格式很簡單,但是有不少缺點的:

1. 隱式類型轉化有些情況下可能會出問題:比如數據精度丟失

2. 顯式類型轉換將所有情況混合在一起,代碼不夠清晰

因此C++提出了自己的類型轉化風格,注意因為C++要兼容C語言,所以C++中還可以使用C語言的轉化風格。


隱式類型轉換

示例:

仍然支持有一定關聯的類型的類型轉換

1.C++內置類型支持轉換為自定義類型

2.C++自定義類型支持轉換成內置類型

單參數的構造函數支持隱式類型的轉換

示例:內置類型 -> 自定義類型

class A
{
public:A(int a1):_a1(a1){}A(int a1, int a2):_a1(a1), _a2(a2){}
private:int _a1 = 1;int _a2 = 1;
};
// 內置類型 -> 自定義類型
A aa1 = 1;
// C++11
A aa2 = {2,2};

示例:自定義類型 -> 內置類型

默認是不支持的,我們需要重載operator int

int x = aa1;
cout << x << endl;

想轉什么類型就寫什么類型: 這里想轉成int,因此就寫int

    operator int(){return _a1 + _a2;}

在OJ當中會遇到這樣的寫法:

while (cin>>x){cout << x << endl;
}

原理是:

	while (cin>>x)while (cin.operator>>(x))while (cin.operator>>(x).operator bool()){cout << x << endl;}

如果想要輸入string呢?

	string str;while (cin>>str){cout << str << endl;}

自定義類型和自定義類型之間的轉換

比如我現在有一個B類型,正常情況下:能否將B類型轉為A類型,不可以,強制類型轉換也不可以

class B
{
public:private:int _b1;
};

解決辦法:用構造函數來支持相關的轉換

class B
{
public:B(const A& aa):_b1(aa.get()){}private:int _b1;
};
	B bb = aa1;

就能支持了(實際上,我們模擬寫const iterator和普通iterator時,就用的這個方法)

隱式類型轉換的坑:

// 隱式類型轉換的坑
void Insert(size_t pos)
{int end = 10;while (end >= pos){cout << end << endl;--end;}
}
//
int main()
{Insert(5);Insert(0);return 0;
}

運行結果:由于隱式類型轉換導致的死循環,原因是因為,這里的int被隱式類型轉換為unsize_int


C++強制類型轉換

標準C++為了加強類型轉換的可視性,引入了四種命名的強制類型轉換操作符: static_cast、reinterpret_cast、const_cast、dynamic_cast

static_cast(對應之前的隱式類型轉換)

static_cast用于非多態類型的轉換(靜態轉換),編譯器隱式執行的任何類型轉換都可用static_cast,但它不能用于兩個不相關的類型進行轉換。

	int i = 1;// 隱式類型轉換 : static_castdouble d = static_cast<double>(i);printf("%d, %.2f\n", i, d);int* p = &i;// error C2440: “static_cast”: 無法從“int *”轉換為“int”// int address1 = static_cast<int>(p);

reinterpret_cast(對應的之前的顯式類型轉換)

reinterpret_cast操作符通常為操作數的位模式提供較低層次的重新解釋,用于將一種類型轉換為另一種不同的類型

示例:

	// 顯示的強制類型轉換 : reinterpret_castint address = reinterpret_cast<int>(p);printf("%p, %d\n", p, address);

之前不支持的還是不會支持?

	// 類型強制轉換”: 無法從“int *”轉換為“double”// double x = (double)p;// 類型強制轉換”: 無法從“int *”轉換為“double”//double x = reinterpret_cast<double> p;

const_cast

const_cast最常用的用途就是刪除變量的const屬性,方便賦值

示例:

	const int a = 1;//a不是存在常量區的,還是在棧上的(常變量// a++;int x = 0;cout << &a << endl;cout << &x << endl;

是可以修改的,間接修改:

	int* ptr = (int*)&a;(*ptr)++;cout << *ptr << endl;cout << a << endl;

為啥用*ptr間接去訪問拿到的是2,直接訪問a又拿到的是1

但是又通過監視窗口,又會發現:a已經被修改了,為什么卻打印1。

這是因為編譯器的優化,第一種是因為:a是const修飾了的,不會被改變,把a存在寄存器中,寄存器中的a值沒有被改變,內存變了,但是取值是直接從寄存器中拿。

第二種是:a直接被替換成 1,類似于宏,在編譯的時候被替換

這個時候就可以在定義a的時候加一個關鍵字:volatile,穩定的。告訴編譯器別優化,每次都到內存當中取

	volatile const int a = 1;

運行結果:

因此增加一個const_cast,來顯式告訴自己,a的const屬性已經被去掉了,他已經可以被改變了,提醒要加上volatile

	int* ptr = const_cast<int*>(&a);

示例:這種情況用哪一種隱式類型轉換方式

	A aa1 = static_cast<A>(1);

這是單參數的構造函數,還是應該走隱式類型的轉換因此使用 static_cast ,reinterpret_cast是顯式類型轉換。


dynamic_cast(專門爭對C++設計的,向下轉換)

dynamic_cast用于將一個父類對象的指針/引用轉換為子類對象的指針或引用(動態轉換)

向上轉型:子類對象指針/引用->父類指針/引用(是天然的,不會產生臨時對象,切片父類,不需要轉換,賦值兼容規則)

向下轉型:父類對象指針/引用->子類指針/引用(用dynamic_cast轉型是安全的)

注意:

1. dynamic_cast只能用于父類含有虛函數的類

2. dynamic_cast會先檢查是否能轉換成功,能成功則轉換,不能則返回0

示例:

class A
{
public:virtual void f() {}int _a1 = 1;
};class B : public A
{
public:int _b1 = 1;
};void fun(A* pa)
{// 無差別轉換,存在一定風險B* pb = (B*)pa;cout << pb << endl;//pb->_b1++;
}int main()
{A a;B b;fun(&a);fun(&b);return 0;
}

這樣轉換是有風險,我們分別給A、B成員_a1,_b1,pa指針有可能只想A對象也有可能指向B對象,如果原本就指向B對象,將你強轉成B是沒有問題的。轉換的時候,現在就指向整個B。如果原來指向A,轉成B之后,會多看一部分,但是那一部分并不屬于pb,越界。

因此C++設計了dynamic_cast來動態轉換:

不是無差別轉換,他會檢查pa原本指向什么對象,如果指向B對象,轉換成功,如果指向A對象,轉換失敗,返回空。能識別是指向父類還是子類。

void fun(A* pa)
{// pa指向B對象,轉換成功// pa指向A對象,轉換失敗,返回空B* pb = dynamic_cast<B*>(pa);if (pb){cout << pb << endl;pb->_b1++;}else{cout << "轉換失敗" << endl;}
}

RTTI(了解)運行時類型識別

RTTI:Run-time Type identification的簡稱,即:運行時類型識別。C++通過以下方式來支持RTTI:

1. typeid運算符

2. dynamic_cast運算符

3. decltype

復習RAII是什么:把一個資源交給一個對象管理,可能是動態開辟的資源,或者鎖,當生命周期到了自動調用析構函數,解鎖、釋放資源

結語:

? ? ? ?隨著這篇博客接近尾聲,我衷心希望我所分享的內容能為你帶來一些啟發和幫助。學習和理解的過程往往充滿挑戰,但正是這些挑戰讓我們不斷成長和進步。我在準備這篇文章時,也深刻體會到了學習與分享的樂趣。 ? ?

? ? ? ? ?在此,我要特別感謝每一位閱讀到這里的你。是你的關注和支持,給予了我持續寫作和分享的動力。我深知,無論我在某個領域有多少見解,都離不開大家的鼓勵與指正。因此,如果你在閱讀過程中有任何疑問、建議或是發現了文章中的不足之處,都歡迎你慷慨賜教 ? ? 。

? ? ? ? 你的每一條反饋都是我前進路上的寶貴財富。同時,我也非常期待能夠得到你的點贊、收藏,關注這將是對我莫大的支持和鼓勵。當然,我更期待的是能夠持續為你帶來有價值的內容。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/77955.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/77955.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/77955.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

探索 Flowable 后端表達式:簡化流程自動化

什么是后端表達式&#xff1f; 在 Flowable 中&#xff0c;后端表達式是一種強大的工具&#xff0c;用于在流程、案例或決策表執行期間動態獲取或設置變量。它還能實現自定義邏輯&#xff0c;或將復雜邏輯委托…… 后端表達式在 Flowable 的后端運行&#xff0c;無法訪問前端…

【Lua】Lua 入門知識點總結

Lua 入門學習筆記 本教程旨在幫助有編程基礎的學習者快速入門Lua編程語言。包括Lua中變量的聲明與使用&#xff0c;包括全局變量和局部變量的區別&#xff0c;以及nil類型的概念、數值型、字符串和函數的基本操作&#xff0c;包括16進制表示、科學計數法、字符串連接、函數聲明…

符號速率估計——小波變換法

[TOC]符號速率估計——小波變換法 一、原理 1.Haar小波變換 小波變換在信號處理領域被成為數學顯微鏡&#xff0c;不同于傅里葉變換&#xff0c;小波變換可以觀測信號隨時間變換的頻譜特征&#xff0c;因此&#xff0c;常用于時頻分析。 ??當小波變換前后位置處于同一個碼元…

android contentProvider 踩坑日記

寫此筆記原因 學習《第一行代碼》到第8章節實現provider時踩了一些坑&#xff0c;因此記錄下來給后來人和自己一個提示&#xff0c;僅此而已。 包含內容 Sqlite數據庫CURD內容provider界面provider項目中書籍管理provider實現邏輯用adb shell確認providercontentResolver接收…

Eureka、LoadBalance和Nacos

Eureka、LoadBalance和Nacos 一.Eureka引入1.注冊中心2.CAP理論3.常見的注冊中心 二.Eureka介紹1.搭建Eureka Server 注冊中心2.搭建服務注冊3.服務發現 三.負載均衡LoadBalance1.問題引入2.服務端負載均衡3.客戶端負載均衡4.Spring Cloud LoadBalancer1).快速上手2)負載均衡策…

【開關電源】關于GaN反激電源開關噪聲

文章目錄 0 前言1 設計信息1.1 設計需求1.2 原理圖1.3 電源表現 2 原因分析3 橫向對比TI UCG28826 &#xff08;GaN&#xff09;采購的普通QR反激變換器 4 總結 0 前言 筆者原計劃設計一款省電的&#xff0c;效率尚可的&#xff0c;穩定的2路輸出反激電源&#xff0c;用于系統…

DOCA介紹

本文分為兩個部分&#xff1a; DOCA及BlueField介紹如何運行DOCA應用&#xff0c;這里以DNS_Filter為例子做大致介紹。 DOCA及BlueField介紹&#xff1a; 現代企業數據中心是軟件定義的、完全可編程的基礎設施&#xff0c;旨在服務于跨云、核心和邊緣環境的高度分布式應用工作…

mybatis mapper.xml中使用枚舉

重點&#xff1a;application.propertis配置類 #TypeEnumHandler 這個類的包名&#xff0c;不是全路徑 mybatis.type-handlers-packagecom.fan.test.handler兩個枚舉類&#xff1a; public enum StatusEnum {DELETED(0),ACTIVE(1);private final int code;StatusEnum(int cod…

鴻蒙生態:鴻蒙生態校園行心得

&#xff08;個人觀點&#xff0c;僅供參考&#xff09; 兄弟們&#xff0c;今天來淺淺聊一聊這次的設立在長沙的鴻蒙生態行活動。 老樣子&#xff0c;我們先來了解一下這個活動&#xff1a; &#xff28;&#xff41;&#xff52;&#xff4d;&#xff4f;&#xff4e;&#x…

【速寫】多LoRA并行衍生的一些思考

遷移學習上的一個老問題&#xff0c;怎么做多領域的遷移&#xff1f;以前的邏輯認為領域遷移屬于是對參數做方向性的調整&#xff0c;如果兩個領域方向相左&#xff0c;實際上不管怎么加權相加都是不合理的。 目前一些做法想著去觀察LoRA權重矩陣中的稠密塊與稀疏塊&#xff0…

【Delphi 基礎知識 44】接口interface的應用

目錄 1. 前言2. 接口有哪些優勢2.1. 實現多態性2.2 實現多重(解決單繼承限制)2.3 解耦代碼(依賴注入)2.4 便于測試(模擬接口)2.5 跨語言互操作性(COM支持)1. 前言 總結為一句話就是:接口只告訴你要做什么,而類會告訴你應該怎么做 下面是最簡單的接口實現 typeIMyIn…

09.傳輸層協議 ——— TCP協議

文章目錄 TCP協議 談談可靠性TCP協議格式 序號與確認序號窗口大小六個標志位 確認應答機制&#xff08;ACK&#xff09;超時重傳機制連接管理機制 三次握手四次揮手 流量控制滑動窗口擁塞控制延遲應答捎帶應答面向字節流粘包問題TCP異常情況TCP小結基于TCP的應用層協議 TCP協…

NLP高頻面試題(五十一)——LSTM詳解

長短期記憶網絡(LSTM)相較于傳統循環神經網絡(RNN)的核心改進在于通過引入記憶單元(cell state)和門機制(gating mechanism)來有效緩解梯度消失與梯度爆炸問題,從而更好地捕捉長距離依賴關系 。在其網絡結構中,信息通過輸入門(input gate)、遺忘門(forget gate)和…

SpringCloud組件—Eureka

一.背景 1.問題提出 我們在一個父項目下寫了兩個子項目&#xff0c;需要兩個子項目之間相互調用。我們可以發送HTTP請求來獲取我們想要的資源&#xff0c;具體實現的方法有很多&#xff0c;可以用HttpURLConnection、HttpClient、Okhttp、 RestTemplate等。 舉個例子&#x…

無需花錢購買域名服務器!使用 VuePress + Github 30分鐘搭建屬于自己的博客網站(保姆級教程)

前言 GitHub Pages 提供免費全球加速的服務器資源&#xff0c;VuePress 將 Markdown 變成藝術品級的網頁&#xff0c;僅需 30 分鐘&#xff0c;你便可以像提交代碼一樣發布文章&#xff0c;過程完全免費。 博客搭建好的效果如下&#xff1a;https://honorsong.github.io/exam…

提交到Gitee倉庫

文章目錄 注冊配置公鑰創建空白的碼云倉庫把本地項目上傳到碼云對應的空白倉庫中 注冊 注冊并激活碼云賬號&#xff08; 注冊頁面地址&#xff1a;https://gitee.com/signup &#xff09; 可以在自己C盤/用戶/用戶名/.ssh 可以看到 有id_rsa.pub 以前在GitHub注冊時搞過&…

如何在 Java 中從 PDF 文件中刪除頁面(教程)

由于 PDF 文件格式不是 Java 原生支持的&#xff0c;因此要從 PDF 中刪除頁面&#xff0c;你需要使用外部庫。 本教程介紹如何使用 JPedal 來實現這一功能。 開始使用 ? 將 JPedal 添加到你的類路徑或模塊路徑中&#xff08;可從官網下載安裝試用版 JAR 文件&#xff09; ?…

機器學習第二篇 多變量線性回歸

數據集&#xff1a;世界幸福指數數據集中的變量有幸福指數排名、國家/地區、幸福指數得分、人均國內生產總值、健康預期壽命、自由權、社會支持、慷慨程度、清廉指數。我們選擇GDP per Capita和Freedom&#xff0c;來預測幸福指數得分。 文件一&#xff1a;linear&#xff0c;…

位運算,狀態壓縮dp(算法競賽進階指南學習筆記)

目錄 移位運算一些位運算的操作最短 Hamilton 路徑&#xff08;狀態壓縮dp模板&#xff0c;位運算&#xff09; 0x是十六進制常數的開頭&#xff1b;本身是聲明進制&#xff0c;后面是對應具體的數&#xff1b; 數組初始化最大值時用0x3f賦值&#xff1b; 移位運算 左移 把二…

Java高頻面試之并發編程-05

hello啊&#xff0c;各位觀眾姥爺們&#xff01;&#xff01;&#xff01;本baby今天來報道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面試官&#xff1a;線程有哪些調度方法&#xff1f; 在Java中&#xff0c;線程的調用方法主要包括以下幾種方式&#xff0c;每種方式適用于…