主頁 > 軟體設計 > C++ 面向物件程式三大特性之 多型

C++ 面向物件程式三大特性之 多型

2021-05-04 09:55:53 軟體設計

目錄

  • 多型的概念
  • 多型的定義及使用
    • 虛函式
      • 虛函式的重寫
      • 虛函式重寫的兩個例外
      • C++11中 override 和 final
      • 多載、重寫、隱藏的區別與聯系
    • 抽象類
  • 多型的原理
    • 虛函式指標、虛函式、虛函式表指標
    • 實作原理
    • 多繼承中的虛函式表
  • 多型零碎知識匯總

多型的概念

不同類的物件對同一訊息作出不同的回應就叫做多型,通俗來講,就是去完成某個行為,當不同的物件去完成時會產生出不同的結果

例如去網吧上機,如果你是vip,那么你上網的價格就會比普通用戶上網的價格低;如果你不是vip,那么你上網的價格就是原價,這就是生活中的一種多型現象

多型的定義及使用

例如以下程式,就是一種多型的體現

class Vip
{
public:
	virtual void online()
	{
		cout << "7折優惠" << endl;
	}
};

class Common : public Vip
{
public:
	virtual void online()
	{
		cout << "全價無優惠" << endl;
	}
};

void fun(Vip& v)
{
	v.online();
}

void test()
{
	Vip v;
	Common m;
	fun(v);
	fun(m);
}

運行結果:
在這里插入圖片描述
vip物件以參考的方式賦值給父類物件v,v呼叫online函式,此時呼叫的是基類的online函式,輸出7折優惠;common物件以參考的方式賦值給父類物件v,v呼叫online函式,此時呼叫的是子類的online函式,輸出全價無優惠;這就體現了不同物件去完成一件事會有不同的結果,這就是多型,那想要實作多型,需要什么必要條件呢?

實作多型的前提(缺一不可)

  1. 多型的體現是體現在基類和派生類中的,所以多型必須有繼承
  2. 該函式必須是虛函式
  3. 虛函式需要被子類重寫
  4. 通過父類的指標或者參考呼叫虛函式,切片操作

前3點都好理解,第四點用代碼解釋

//多型
void fun(Vip& v)
{
	v.online();
}
void fun1(Vip* v)
{
	v->online();
}

//非多型
void fun2(Vip v)
{
	v.online();
}

在這里插入圖片描述

虛函式

在函式名面前加上關鍵字virtual,則該函式就為虛函式,
格式:virtual 回傳值 函式名(引數)

class Vip
{
public:
	virtual void online()
	{
		cout << "7折優惠" << endl;
	}
};

虛函式的重寫

虛函式的重寫(覆寫):派生類中有一個跟基類完全相同的虛函式稱子類的虛函式重寫了基類的虛函式

重寫(覆寫)要求:派生類中的虛函式要與基類中的虛函式的函式名引數串列回傳值都要完全相同

虛函式在多型中的注意事項:在重寫基類虛函式時,派生類的虛函式在不加virtual關鍵字時,雖然也可以構成重寫,但是該種寫法不是很規范,不建議這樣使用(因為繼承后基類的虛函式被繼承下來了在派生類依舊保持虛函式屬性)

虛函式重寫的兩個例外

1、協變(回傳值不同)
派生類重寫基類虛函式時,與基類虛函式回傳值型別可以不同,但是回傳值型別必須是有繼承關系的指標或者參考

class A //基類A
{};

class B : public A //派生類B
{};
class Vip
{
public:
	virtual A* online() //回傳值是基類的指標,且必須是基類的指標
	{
		cout << "7折優惠" << endl;
		return new A;
	}
};

class Common : public Vip
{
public:
	virtual  B* online()//回傳值是派生類的指標,且必須是派生類的指標
	{
		cout << "全價無優惠" << endl;
		return new B;
	}
};

運行結果:
在這里插入圖片描述
2、解構式的重寫(名字不同)
如果將基類的解構式置為虛函式,那么派生類中的顯示定義的解構式無論是否是虛函式,都與基類中的解構式構成了重寫,因為在底層,編譯器對解構式名做了特殊處理,在底層的名字都為destructor,所以構成了重寫

我們來看以下代碼

class Vip
{
public:
	virtual void online()
	{
		cout << "7折優惠" << endl;
	}
	~Vip()
	{
		cout << "~Vip" << endl;
	}
};

class Common : public Vip
{
public:
	virtual void online()
	{
		cout << "全價無優惠" << endl;
	}
	~Common()
	{
		if (_name)
		{
			delete[] _name;
			cout << "delete[] _name" << endl;
		}
		cout << "~Common" << endl;
	}
private:
	char* _name = new char[100];
};

運行結果:此時并不會釋放子類中的資源,產生了記憶體泄漏的問題
在這里插入圖片描述
要想防止記憶體泄漏,就必須使解構式有多型的行為,在基類中的解構式置為虛函式,使此解構式與派生類中的解構式構成重寫

	virtual ~Vip()
	{
		cout << "~Vip" << endl;
	}

運行結果:這樣子就不會發生記憶體泄漏了
在這里插入圖片描述
為什么解構式要被定義成虛函式?
:實作多型時,我們通過基類指標指向子類物件,在delete基類指標時,我們希望先呼叫子類的解構式,再呼叫父類的解構式,要實作這個目的,解構式就必須定義成虛函式,否則只會呼叫父類的解構式,子類的解構式不會被呼叫

C++11中 override 和 final

如果我們在寫多型的代碼時,由于我們的疏忽,將函式的名字、回傳值或者引數寫錯了,此時就無法構成重寫,而這種錯誤在編譯期間是不會報錯的,只有在程式運行時才能發現,這時候為了解決這種問題,C++11引入了兩個關鍵字overridefinal

override
格式:重寫的函式 override ----用在派生類中的虛函式
作用:檢查派生類虛函式是否重寫了基類某個虛函式,如果沒有重寫編譯報錯

class Vip
{
public:
	virtual void online() 
	{
		cout << "7折優惠" << endl;
	}
};

class Common : public Vip
{
public:
	//介面繼承,不繼承基類中的實作,需要自己重寫實作
	virtual void online() override
	{
		cout << "全價無優惠" << endl;
	}
};

在這里插入圖片描述
final
格式1:class 類名 final ----用在基類中
格式2:函式名 final ----用在基類中的虛函式
作用:1、被final修飾的類不能被繼承;2、被final修飾的虛函式不能被重寫

class A final
{};
class B : A
{};

在這里插入圖片描述

class Vip
{
public:
	//定義繼承,將該函式的實作也繼承過去且無法修改
	virtual void online() final
	{
		cout << "7折優惠" << endl;
	}
};

class Common : public Vip
{
public:
	
	virtual void online()
	{
		cout << "全價無優惠" << endl;
	}
};

在這里插入圖片描述

多載、重寫、隱藏的區別與聯系

函式多載:同一作用域內被宣告的幾個具有不同引數的同名函式,根據引數串列確定呼叫哪個函式,且不關心函式的回傳值
函式隱藏:是指派生類的函式屏蔽了與其同名的基類函式,只要同名函式,不管引數串列是否相同,基類函式都會被隱藏
重寫覆寫:是指派生類中存在重新定義的函式,其函式名,引數串列,回傳值型別,所有都必須同基類中被重寫的函式一致,只有函式體不同,派生類呼叫時會呼叫派生類的重寫函式,不會呼叫被重寫函式,重寫的基類中被重寫的函式必須有virtual修飾

類別作用域函式名引數串列回傳值型別是否有virtual修飾
函式多載同一作用域相同不同無要求無要求
函式隱藏不同作用域(父類和子類)相同無要求無要求父類函式不能有virtua
重寫覆寫不同作用域(父類和子類)相同相同相同(協變除外)父類函式必須有

抽象類

純虛函式的定義:在虛函式的后面寫上=0 ,則這個函式為純虛函式

//純虛函式
virtual void fun() = 0
{}

抽象類的定義:包含純虛函式的類叫做抽象類(也叫介面類)

//抽象類
class A
{
public:
	//純虛函式
	virtual void fun() = 0
	{}
};

class B : public A
{
public:
	virtual void fun()
	{
		cout << "B::fun()" << endl;
	}
};

class C : public A
{
public:
	virtual void fun()
	{
		cout << "C::fun()" << endl;
	}
};

注意:抽象類不能實體化出物件,派生類繼承后也不能實體化出物件,只有重寫純虛函式,派生類才能實體化出物件

class D: public A
{};

在這里插入圖片描述
抽象類具有規劃性,如假如你要去網吧上網,那么你必須提供身份證,也就是派生類必須提供重寫提供身份證的這個虛函式,如果不提供,就不能上網,不重寫,也就是不能使用該類
引入純虛函式的目的
1、為了方便使用多型特性,我們常常需要在基類中定義虛擬函式
2、在很多情況下,基類本身生成物件是不合情理的,例如,動物作為一個基類可以派生出老虎、孔雀等子類,但動物本身生成物件明顯不合常理
  為了解決上述問題,引入了純虛函式的概念,將函式定義為純虛函式,則編譯器要求在派生類中必須予以重寫以實作多型性,同時含有純虛擬函式的類稱為抽象類,它不能生成物件,這樣就很好地解決了上述兩個問題

多型的原理

虛函式指標、虛函式、虛函式表指標

我們先來看看以下類中的大小

class Base
{
public:
	virtual void fun()
	{
		cout << "fun()" << endl;
	}
protected:
	int _a = 1;
};

運行結果:
在這里插入圖片描述
我們發現是8個位元組,為什么會是8個位元組呢?難道函式也占用空間了嗎?我們創建一個Base物件看看這個物件中都包含了哪些成員
在這里插入圖片描述
我們可以發現,在物件b中不僅包含了自己定義的一個成員變數_a,好包含了一個void**型別的指標,所以大小才會8個位元組,那為什么會有這個指標呢?那肯定跟這個虛函式脫不了關系,其實這個指標就是虛函式表指標----__vfptr(v代表virtual,f代表 function,ptr代表指標),我們再來看看虛函式表指標里的內容
在這里插入圖片描述
虛函式表指標指向的是一個虛表----vftable,也就是說虛表指標是虛表的首地址 ,而虛表中存放的是虛函式指標,虛函式指標也就是就是虛函式的地址,所以虛表也就是一個指標陣列
我們再來分析一下虛函式指標和虛函式表的關系

class Base
{
public:
	virtual void fun1()
	{
		cout << "fun1()" << endl;
	}
	virtual void fun2()
	{
		cout << "Base::fun2()" << endl;
	}
	void fun3()
	{
		cout << "Base::fun3()" << endl;
	}
private:
	int _b = 1;
};

class Derive : public Base
{
public:
	virtual void fun1()
	{
		{
			cout << "Derive::fun1()" << endl;
		}
	}
private:
	int _d = 2;
};

創建Base物件和Derive物件,查看他們的虛表指標,我們在基類中創建了兩個虛函式,而虛函式指標會存放在虛表中,虛表中的兩個元素,第一個元素是就是fun1的虛函式指標,第二個元素就是fun2的虛函式指標
在這里插入圖片描述
我們畫一幅圖來形象理解虛表指標、虛表、虛函式指標、虛函式的關系
在這里插入圖片描述

搞懂了虛表指標和虛表的關系后我們再來看看派生類中的虛表指標,派生類中也有一個虛表指標,派生類繼承了基類的虛表,也就是將基類中的虛表拷貝一份,再用一個新的虛表指標指向該虛表,派生類當存在同名、回傳值、引數串列都相同的虛函式時,會將虛表中的相同虛函式指標給覆寫掉,所以重寫也可以叫做覆寫,原因就是這樣子得來的,例如派生類中的fun1重寫基類中的fun1,此時派生類中的虛表存放的就是派生類fun1的虛函式指標,所以之所以可以產生多型行為,其實就是派生類中的虛函式指標覆寫了基類中的指定的虛函式指標,從而呼叫時就會呼叫派生類的虛函式了
在這里插入圖片描述
但是我們要知道,其實虛表不是存放在物件當中的,只有虛表指標才存放在物件中,我們先證明物件中只存放虛表指標而不存放虛表,我們知道虛表的大小是和虛函式的個數有關,那么我們創建不同個數的虛函式的類,他的大小如果一樣,那么就表示虛表是不存放在物件中的,反之存在,

class A
{
public:
	virtual void fun1()
	{
		cout << "fun1()" << endl;
	}
	virtual void fun2()
	{
		cout << "fun2()" << endl;
	}
private:
	int _a = 1;
};

class B
{
public:
	virtual void fun3()
	{
		cout << "fun3()" << endl;
	}
private:
	int _a = 2;
};

運行結果:我們發現即使虛函式的個數不同,類的大小都是相同的,也就表明虛表是不存放在類中的
在這里插入圖片描述
我們再總結理一理虛表指標、虛函式指標、虛函式它們各自存放的位置,虛表指標是存放在一個物件中的起始位置或者末尾位置(平臺不同位置不同,一般是起始位置);虛函式指標是存放在虛表中的;虛函式和普通函式一樣,都是存放在代碼段中的那虛表到底存在哪里呢?

在我們程式員能用的到的記憶體有堆疊、堆、資料段、代碼段,也就是所虛表肯定存在在這四個記憶體中的其中一個,那么我們如何判斷呢?我們可以粗糙得查看地址的遠近,查看虛表的地址和那塊記憶體的地址相近,最相近的那地址,也就可以認為是在那一塊記憶體中

void test()
{
	int a = 10; //堆疊
	int* ptr = new int;//堆
	static int s = 1; //資料段
	const char* str = "123"; //文字常量區/代碼段
	cout << "堆疊:" << &a << endl;
	cout << "堆:" << ptr << endl;
	cout << "資料段:" << &s << endl;
	printf("代碼段:%p\n", str);
}

運行結果:堆疊和堆地址相差還是很大的,而資料段和代碼段的地址相差也不小,這四個地址都分別代表了記憶體中的不同位置,我們接下來在列印虛表的地址,看看和哪個地址接近
在這里插入圖片描述
但是現在的問題是,我們如何拿到虛表的地址,我們來分析分析
1、先取b的地址,強轉成一個int* 的指標,獲取到類的前4個地址,也就獲得了虛表指標的地址;

Base b;
&b;
(int*)&b

2、再解參考取值,就取到了b物件頭4bytes的值,這個值就是指向虛表的指標,也就是虛表的首地址

*(int*)b;

3、但是這個值是int型別的值,我們必須強轉為虛表存放的型別,虛表存放的型別也就是虛函式指標,我們這里定義的虛函式是無引數無回傳值的函式,此時我們就拿到了虛表的地址

//虛函式指標變數
//沒有回傳值,引數串列為空的指標
typedef void(*vfptr)();
vfptr* vfp = (vfptr*)(int*)&b;

運行結果:我們可以推出
在這里插入圖片描述
我們發現虛表的地址更接近資料段的地址,所以虛表存放在資料段中,虛函式表本質是一個存虛函式指標的指標陣列,這個陣列最后面放了一個nullptr

實作原理

如何找到虛函式?
1、從物件中獲取虛表指標
2、通過虛表指標找到虛表
3、從虛表中找到虛函式的地址
4、執行虛函式的指令
在這里插入圖片描述
我們再通過匯編來看代碼的執行
在這里插入圖片描述
第一行:v中存的是v物件的指標,將v移動到eax中
第二行:[eax]就是取eax值指向的內容,這里相當于把vip物件頭4個位元組(虛表指標)移動到了edx
第五行:[edx]就是取edx值指向的內容,這里相當于把虛表中的頭4位元組存的虛函式指標移動到了eax
第六行:call eax,呼叫虛函式
這里可以看出滿足多型的呼叫,不是在編譯時確定的,是運行起來以后到物件的中取找的

我們來獲取虛表中的虛函式,執行并列印

class Base
{
public:
	virtual void fun1()
	{
		cout << "Base::fun1()" << endl;
	}
	virtual void fun2()
	{
		cout << "Base::fun2()" << endl;
	}
private:
	int _b = 1;
};

class Derive : public Base
{
public:
	virtual void fun1()
	{
		cout << "Derive::fun1()" << endl;
	}
	virtual void fun3()
	{
		cout << "Derive::fun3()" << endl;
	}
	virtual void fun4()
	{
		cout << "Derive::fun4()" << endl;
	}
private:
	int _d = 2;
};

typedef void(*vfptr)();
void printfVftable(vfptr vtable[])
{
	cout << "虛表地址:" << vtable << endl;
	//訪問虛表元素:虛函式指標
	vfptr* fptr = vtable;
	while (*fptr != nullptr)
	{
		(*fptr)();
		++fptr;
	}
}

在這里插入圖片描述

多繼承中的虛函式表

在多繼承中,都會繼承每個類的虛表
在這里插入圖片描述
我們先來看看第一個虛表的地址,并執行虛表中的虛函式

class Base1 {
public:
	virtual void func1() { cout << "Base1::func1" << endl; } 
	virtual void func2() { cout << "Base1::func2" << endl; }
private: int b1;
};

class Base2 {
public:
	virtual void func1() { cout << "Base2::func1" << endl; } 
	virtual void func2() { cout << "Base2::func2" << endl; }
private: int b2;
};

class Derive : public Base1, public Base2 {
public:
	virtual void func1() { cout << "Derive::func1" << endl; } 
	virtual void func3() { cout << "Derive::func3" << endl; }
private: int d1;
};

運行結果:func2函式是使用的是第一個父類的虛函式
在這里插入圖片描述
我們再來看看第二個虛表的地址,我們如何獲得第二個虛表的地址呢?此時我們就必須要偏移base1這個類的大小的距離
在這里插入圖片描述
我們就可以看到第二個虛表的虛函式了,并且子類的fun1函式也將第二個虛表的fun1覆寫了,但是我們發現fun3只在第一個虛表中出現,并不在第二個虛表中出現,所以可以說是,新定義的虛函式指標都會默認放到第一個虛表中,所以fun3指標只會存放第一個虛表中

多型零碎知識匯總

1、virtual關鍵字只在宣告時加上,在類外實作時不能加
2、static和virtual是不能同時使用的
3、靜態成員函式屬于整個類,不能被重寫,不能設定為虛函式,虛表指標是存在物件中的,通過類名是拿不到虛表指標的
4、編譯時的多型性可通過函式多載和模板實作;運行時的多型性可通過虛函式實作
5、一個類的不同物件共享該類的虛表
6、虛表是在編譯期間生成的
7、多繼承的時候,就會可能有多張虛表
8、純虛函式不一定是空函式,只是寫函式體的意義不大
9、行內函式不能是虛函式,因為inline函式沒有地址,無法把地址放到虛函式表中
10、如果存在虛函式和虛擬繼承,物件的前4個位元組依然是虛表指標,緊接后面的是虛基表指標
11、建構式是不能是虛函式的,虛函式的執行依賴于虛函式表,而虛函式表在建構式中進行初始化作業,即初始化vptr,讓他指向正確的虛函式表,而在構造物件期間,虛函式表還沒有被初始化,將無法進行
12、如果是普通物件,呼叫普通函式和虛函式的速度是一樣快的;如果是參考或者指標,由于構成多型,運行呼叫虛函式需要到虛函式表中去查找,則普通函式更快

class Base1 { public: int _b1; }; 
class Base2 { public: int _b2; }; 
class Derive : public Base1, public Base2 { public: int _d; };
int main(){
	 Derive d; 
	 Base1* p1 = &d;  //*p1=_b1
	 Base2* p2 = &d;  //*p2=_b2
	 Derive* p3 = &d;   //*p3=_b1
	 //p1 == p3 != p2
	 return 0;
}
class A {
public:
	virtual void func(int val = 1)
	{ std::cout<<"A->"<< val <<std::endl;} 
	virtual void test(){ func();}
};
class B : public A {
	public: void func(int val=0)
	{ std::cout<<"B->"<< val <<std::endl; }
};
int main(int argc ,char* argv[]) {
	B*p = new B;
	p->test(); 
	//B->1,A類中的func才是真正的定義
	//而B類中是對func的重寫,編譯器看到是重寫時,不看預設值,只看定義
	return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/282666.html

標籤:其他

上一篇:第二講:PN結與二極管的特性

下一篇:資料結構(二):鏈表

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more