主頁 > 後端開發 > 現代C++學習指南-具體類

現代C++學習指南-具體類

2023-06-22 07:41:49 後端開發

類作為C++中重要的概念之一,有著眾多的特性,也是最迷人的部分!

類是一個加工廠,開發者使用C++提供的各種材料組裝這個工廠,使得它可以生產出符合自己要求的資料,通過對工廠的改造,可以精細控制物件從出生到死亡的各種行為,真正達到我的代碼我做主的境界,

我們經常說的面向物件三大特征:封裝,繼承和多型,其實說的是一種抽象維度,最簡單的就是具體類,它將資料打包在一起,提供操作資料的函式,使得開發者不再需要通過傳參的形式傳遞資料,它實作了事物的抽象,也就是所謂的封裝,第二層是在一堆資料中提取出共性的部分作為基類,然后將特性作為子類,充分利用繼承的優點,實作代碼復用,它不僅追求資料抽象,也追求行為上的相似性,而更進一步,一套演算法不關心實際的資料,只關心它可以用來完成什么作業,甚至相互都不知道對方的存在,唯一的共同點就是都繼承自某個類,都能完成那個類指定的操作,至于細節都不關心,這就是多型,類只是一種規范流程,從第一層到第三層,抽象的事物從具體轉向抽象,重心也從資料轉向行為,只是為了更好的可維護性和解耦性,三者的關系可能是下圖這樣的:

為了能將跟高級的繼承和多型講明白,本篇我們將著重介紹他們的第一形態:封裝,也就是具體類,

類的基本組成

類是一種自定義型別,主要由兩部分組成:成員變數保存類管理的資料,成員函式操作資料,
和普通變數相比,類中的成員變數最大的不同是其生命周期,成員變數在類實體化后才占用空間,建構式完成其初始化作業,在構造完成后,成員函式就可以無限制地使用成員變數,直到解構式被呼叫,
成員函式和普通函式的不同之處是成員函式有個隱含的this指標,這個指標指向成員變數的存盤位置,也就是可以很方便地完成成員變數的訪問,
由此可見,具體類研究的主體是資料,接下來我將圍繞著資料的生命周期完成對類特性的決議,

物件的創建和銷毀

類的第一大作用就是控制類怎么生成和銷毀,和Java不同,不需要用new也會涉及到建構式的呼叫,哪怕只是個普通的區域變數,出了變數的作用范圍,物件就會被銷毀,記憶體就會被釋放,

class Sample{
 public:
    Sample(){
        std::cout<<"Creating a Sample object"<<std::endl;
    }
    
    ~Sample(){
        std::cout<<"Destoring a Sample object"<<std::endl;
    }
};

int main(){
    // Sample的建構式被呼叫
    Sample a; 
    {
        // 大括號創建了一個區域作用域,物件b只存在大括號范圍內,出了大括號后,b就會被銷毀,呼叫Sample的解構式
        Sample b;
    }
    // 此時只有物件a還存活
}
// 輸出
// Creating a Sample object
// Creating a Sample object
// Destoring a Sample object
// Destoring a Sample object

上面的Sample是最簡單的類定義,我們只創建了類的建構式和解構式,在main函式中,創建了兩個變數,通過檢查輸出,我們可以確定類的建構式和解構式都被呼叫了,
上面那個類從功能上毫無用處,我們只能創建一個它的物件,然后看著它死去,什么也干不了,接下來,我們來改造下Sample類,讓它能在構造的時候告訴我們,哪一個物件在構造,

class Sample{
    Sample(const std::string name){
            std::cout<<"Creating a Sample object:name = "<<name<<std::endl;
        }
    //其余不變
};

int main(){
    // 由于創建物件a時,用到了string物件,所以要先創建一個string物件
    std::string str{"a"};
    // 此時構造類需要一個名字了,我們已經控制了類的初始化狀態
    Sample a{str}; 
    {
        // Sample唯一給建構式需要一個string的物件,但是編譯器推測出傳遞給Sample建構式的引數型別是字串常量
        // 引數不匹配,但這還沒達到編譯失敗的條件,因為編譯器還沒檢查是否存在一種從字串常量生成字串物件的建構式,
        // 答案是有的,string類提供了這樣的建構式
        // 接下來編譯器用字串常量構造出了string物件,自動完成了string物件的創建
        // 并傳遞給Sample的建構式,條件滿足,編譯順利完成
        Sample b{"b"};
    }
}
// 輸出
// Creating a Sample object:name = a
// Creating a Sample object:name = b
// Destoring a Sample object
// Destoring a Sample object

上面的例子有一個值得注意的地方,那就是物件b直接從字串常量創建出來了,省略了中間字串物件,其實這一步是編譯器為我們完成了,它的創建程序和a是完全一樣的,這種行為稱為隱式轉換,
這時的Sample類還是什么也做不了,甚至連哪一個物件被銷毀了我們都不知道,解構式是函式,那么給解構式添加引數行不行呢?答案是不行,因為解構式是編譯器自動幫我們呼叫的,它不知道呼叫時需要什么引數,所以就只能是無參,那么有什么辦法能正確標記出是哪個物件被銷毀了呢,答案是成員變數,
成員變數和物件是同生共死的,它和物件使用同一塊記憶體,物件創建就為成員變數也分配了空間,但是沒有初始化,需要開發者在建構式或者其他函式使用前初始化,在解構式呼叫時,記憶體尚未被回收,這時候是使用成員變數的最后時機,成員變數還有另一個重要的特點,在類中定義的所有非static函式都能使用它,不需要通過函式引數傳遞,這也是類設計的初衷之一,用類管理資料,
所以,接下來的解構式可以這樣寫

class Sample {
private:
    // 第一步,創建一個成員變數
    std::string name;
public:
    // 第二步,在建構式中初始化成員變數
    Sample(const std::string name) :name{ name } {
        std::cout << "Creating a Sample object:name = " << name << std::endl;
    }

    ~Sample() {
        //第三步,使用成員變數
        std::cout << "Destoring a Sample object:name = " << name << std::endl;
    }
};

int main() {
    std::string str{ "a" };
    Sample a{ str };
    {
        Sample b{ "b" };
    }
}
// 輸出
// Creating a Sample object:name = a
// Creating a Sample object:name = b
// Destoring a Sample object:name = b
// Destoring a Sample object:name = a

可以看到,創建成員變數也很簡單,關鍵在于第二步,這和Java又不一樣,第二步中,初始化成員變數使用了特殊的語法,在建構式小括號后面添加了:,然后普通變數初始化的語法,稱之為成員變數初始化,這樣寫的關鍵原因在于,物件創建需要先申請記憶體,記憶體申請后使用:后面的初始化方式初始化成員變數,最后才呼叫建構式完成物件的創建,每一步都有它對應的位置和作用,假如像Java一樣寫在建構式里面,就相當于將第二步放到了第三步,打亂了它本來的順序,
為了說明成員函式確實在物件的整個生命周期都可以使用,我們再個它添加一個成員函式吧,

class Sample{
    void print() {
        std::cout << "Invoke print name = " << name << std::endl;
    }
    //其余不變
}
int main() {
    std::string str{ "a" };
    Sample a{ str };
    {
        Sample b{ "b" };
        b.print();
    }
    a.print();
}
// 輸出
// Creating a Sample object:name = a
// Creating a Sample object:name = b
// Invoke print name = b
// Destoring a Sample object:name = b
// Invoke print name = a
// Destoring a Sample object:name = a

我們添加了一個成員函式print它沒有引數,但是它的函式體使用了成員變數name,可以看到,它也能正常作業,
至此,物件的創建和銷毀就說得差不多了,還沒說到的是建構式可以有很多個,在創建物件的時候可以選擇使用哪種方式創建,編譯器會根據傳遞的引數來推匯出實際使用的建構式,開發者需要考慮的是提供的建構式都能完成成員函式的正確初始化,以便在呼叫成員函式時,成員函式都能按預期作業,如Sample,我們還可以提供一個無參的建構式,然后將name初始化為空字串,這樣print和解構式也能正常作業,
總結一下,類是管理資料的容器,它的資料隨著物件的創建而創建,并在物件存在的整個生命周期都可用,建構式需要保證資料的初始化,并可以控制它構造的方式,成員函式可以隨時使用,解構式是物件銷毀時最后一個呼叫,它需要保證資料到此都被清理,

資料的轉移和共享

資料拷貝

資料創建之后,不僅可以供成員函式使用,還可能被轉移到其他物件中去,或者和其他物件共享,復制建構式可以控制資料以怎樣的方式和其他物件共享,

class Sample {
private:
    int value;
public:
    Sample(const int value) :value{ value } {
        std::cout << "Create value = "https://www.cnblogs.com/honguilee/archive/2023/06/21/<< value << std::endl;
    }

    // 以Sample命名,是建構式,函式引數是自己的型別,說明是復制建構式
    // 這個復制建構式選擇用賦值的形式共享value資料
    Sample(const Sample& sample) :value{ sample.value } {
        std::cout <<"Copy create object" << std::endl;
    }

};

void use(Sample sample) {
    //函式回傳,sample物件被銷毀
}

int main() {
    Sample a{ 1 };
    // a的資料被分享給一個臨時物件了,此時出現了兩個物件,它們的value都是1
    use(a);
}
// 輸出
// Create value = https://www.cnblogs.com/honguilee/archive/2023/06/21/1
// Copy create object

復制建構式有以下幾個特征

  1. 會出現至少兩個同型別的物件,因為復制需要先有一個存在的物件,再用這個存在的物件資料初始化另一個正在創建的物件的成員變數,這也是復制建構式引數是自己的原因,
  2. 存在變數從無到有初始化的情況都會呼叫復制建構式,函式呼叫,形參需要初始化為實參,引數本來不存在,呼叫函式會傳遞一個已存在的物件,就會呼叫到復制建構式,這也是為什么復制建構式引數是參考的型別,假如是普通變數,呼叫復制構造的時候需要產生臨時變數,臨時變數又需要呼叫復制建構式,程式就會陷入無限遞回中,
  3. 除了函式呼叫,函式回傳值,用物件初始化新變數的情況也會呼叫到復制建構式,函式回傳后,函式體中所有的區域變數都會被銷毀,回傳值也屬于一種區域變數肯定也要被銷毀,但是回傳后的值卻需要被 外部使用,它們的生命周期是不一樣的,由此我們就知道肯定創建了一個新的物件,這個物件被區域回傳值初始化,但是有著和外部一樣的生命周期,用物件初始化變數就更直觀了,初始化的物件是從無到有創建的,符合建構式出現的特點,

我們可以來驗證一下

//其余不變
Sample returnSample() {
    // 用普通建構式初始化的
    Sample sample{ 2 };
    return sample;
}
int main() {
    Sample a{ 1 };
    std::cout << "init local variable" << std::endl;
    // b是新物件,用a初始化的,所以呼叫了復制建構式
    Sample b = a;
    // use的形參被用來初始化
    std::cout << "Use Sample as parameter" << std::endl;
    use(a);
    //回傳的sample被用來初始化c
    std::cout << "return sample" << std::endl;
    Sample c = returnSample();
}
// 輸出
// Create value = https://www.cnblogs.com/honguilee/archive/2023/06/21/1
// init local variable
// Copy create object
// Use Sample as parameter
// Copy create object
// return sample
// Create value = 2
// Copy create object

可以看到,這三種情況都會造成復制建構式的呼叫,

資料移動

資料拷貝雖然簡單易行,但是還是有個小瑕疵,考慮下面這種場景:

void swap(Object& left,Object& right){
    // 有新物件產生,拷貝構造,目前記憶體中有兩份一模一樣的left
    Object temp=left;
    // 賦值操作,生成了一個right的臨時物件
    left=right;
    // 賦值操作,生成了一個temp的臨時物件
    right=temp;
    // 三個臨時物件都被銷毀
}

int main(){
    Object a;
    Object b;
    swap(a,b);
    return 0;
}

一個簡單的交換邏輯,我們就生成了很多的臨時物件,假如我們操作的是串列,大物件,短時間內大量創建并銷毀物件,就會造成記憶體抖動,嚴重影響系統的穩定性,而且,我們的真正目的只是將兩個變數的值交換一下而已,所以相較于拷貝,我們還有更好的選擇:移動,

左值和右值

說起移動,就不得不提到左值和右值,這里的左和右是相對于=來說的,
我們知道=是用來賦值的,這下面隱藏著三個動作:生,取,寫,在記憶體中生成一個臨時資料,讀取變數保存位置,將臨時變數內容寫入保存位置,生就是指的右值,它保存在我們不知道的記憶體位置,在寫動作完成后,它就被回收了,而取對應的就是左值,我們用變數名保存了它的記憶體位置,在它作用域內可以反復讀寫,所以右值最大的特點就是不知道地址,如i=i+1就會先生成一個i+1的臨時物件,我們不知道地址,所以它是右值,與之相對的左值,是可以通過&讀到地址的,
接下來我們再來談一談參考,我們通常是用別名來理解參考的,但是可能會忽略一個小細節,別名也是需要有歸屬的,也就是它代表的地址在哪里,基于這個前提,我們就可以推匯出凡是存在記憶體中的資料,理都是有地址的,而右值是存在記憶體中的,它也應該需要一種方式來獲得地址,稱之為右值參考,相對的一般變數的參考就稱為左值參考,
說回到移動,前面的復制建構式雖然能將資料和其他物件共享,但是大部分情況下,資料其實不需要共享的,只需要轉移,也就是將資料的所有權移動到另一個物件上,原始物件就不再有效,所以C++提供了移動建構式來完成這個操作,

class Sample {
private:
	int* value;

public:
	Sample(const int value) :value{ new int{value} } {
		std::cout << "Create value = "https://www.cnblogs.com/honguilee/archive/2023/06/21/<< value << std::endl;
	}

	Sample(const Sample& sample) :value{ new int {*sample.value} } {
		std::cout <<"Copy create object" << std::endl;
	}

	Sample(Sample&& sample) :value{ sample.value } {
		sample.value = https://www.cnblogs.com/honguilee/archive/2023/06/21/nullptr;
		std::cout <<"Move create object" << std::endl;
	}

	~Sample() {
		delete value;
		std::cout << "destory sample" << std::endl;
	}

	friend std::ostream& operator<<(std::ostream& os, const Sample& sample) {
		os << "Sample value is " << sample.value;
		return os;
	}

};

void use(Sample sample) {
	std::cout << "Use sample " << sample << std::endl;
}


int main() {
	// 普通變數,1被使用后馬上銷毀了
	int a = 1;
	//左值參考
	int& b = a;
	//右值參考,參考的就是1那個暫存的地址
	int&& c = 1;
	//可以修改參考的值
	c = 2;

	Sample sample{ 1 };

	use(std::move(sample));

	std::cout << sample << std::endl;
}
// 輸出
// Create value = https://www.cnblogs.com/honguilee/archive/2023/06/21/1
// Move create object
// Use sample Sample value is 009B8E90
// destory sample
// Sample value is 00000000
// destory sample

在上面的代碼里,我們真正使用sample物件的是函式useuse執行完后,sample就沒用了,所以我們用std::move將資料轉移到了函式實參中,外部的sample不再擁有那塊記憶體的占用,很多場景其實都是類似的情況:外部配置引數后,傳遞給某個函式使用,所以這種情況下就沒必要構造一個新的物件出來,假如業務很長的話,sample物件就會一直占用記憶體,但是它是早就沒用了的,所以移動建構式就發揮了大作用,

資料共享

除了通過復制建構式和成員函式共享資料外,還可以通過友元類和友元函式,它們都是一種特殊的訪問資料的形式,可以直接訪問到資料,不經過成員函式的呼叫,所以在有些時候友元能幫助減少函式呼叫的花銷,有些時候則會引入不可預期的行為,

class FriendClass {

public:
    void useSample(const Sample& sample) {
        std::cout << "Sample value is " << sample.value << std::endl;
    }
};

上面的例子,如果按照常規是無法通過編譯的,因為samplevalue是私有的,前面我們知道,成員函式是可以訪問私有變數的,但是這個類是定義在Sample外的,這個函式是另一個類的成員函式,完全沒辦法完成這種訪問,當然,這種情況下,我們可以修改Sample類的定義,添加一個成員函式就解決了,但是假如FriendClass有多個成員函式都需要訪問Sample的私有成員呢,這個時候添加成員函式的方式就不再適用,所以出現了友元類,
實作友元類很簡單,簡單到只需要添加一條宣告,首先友元類需要至少兩個類,一個類是想要訪問私有成員的源類,另一個是含有私有成員的目標類,然后我們把友元宣告放在目標類里,源類就可以順利訪問到目標類的私有成員了,在上面的例子FriendClass想要訪問Sample的私有成員,所以它是源類,是普普通通的類,Sample含有FeiendClass想訪問的私有成員value,所以它是目標類,宣告需要添加到它的類定義里面,

Class Sample{
    private:
    int value;
    friend class FriendClass;
    
    //其余不變
}

加上這一條之后,前面的FriendClass就可以正常通過編譯了,這一句的威力很大,大到FriendClass的所有成員函式都能訪問到value,假如這不是你的期望,但是還是想要直接訪問到value,那么就可以適用友元函式,
友元函式是普通的函式,雖然它宣告在類里,但是不能直接訪問到類的私有成員,而是通過函式引數的形式,為了和普通的成員函式區分開來,它的宣告最前面需要添加關鍵字friendfriend仿佛像打開了權限控制的開關,可以使函式訪問到引數的私有成員,

class Sample{
    friend std::ostream& operator<<(std::ostream& os,const Sample& sample) {
        os << "Sample value is " << sample.value << std::endl;
        return os;
    }
    //其余不變
}

int main() {
    Sample a{ 1 };
    std::cout << a << std::endl;
}

// 輸出
// Create value = https://www.cnblogs.com/honguilee/archive/2023/06/21/1
// Sample value is 1

函式<<是友元函式,因為函式宣告有關鍵字friend,友元函式不是成員函式,想在函式體訪問到成員變數,需要添加函式引數,那么函式引數有很多個,怎樣確定引數私有成員的可訪問性呢,這就得看這個友元函式宣告在哪個類里面了,友元函式的宣告位置直接確定了它訪問私有成員的范圍,

特殊的成員函式

C++的類有極大的定制性,這種定制性不僅僅表現在資料上,還表現在成員函式上,我們知道一般的成員函式都是使用.來呼叫的,但是出于特殊的場景,有些情況下這種呼叫形式不僅僅不直觀,還效率不高,所以C++提出了運算子的概念,之所以稱為運算子,是因為函式的呼叫和傳參形式和普通的成員函式不一樣,定義良好的運算子可大大提高代碼的可讀性,如

  • []運算子是下標運算子,有了它的幫助,我們就可以像obj[2]這樣取容器中的元素了,
  • ()則可以把物件當成函式一樣直接呼叫,實作函式式編程的效果,
  • ->可以回傳另外的物件,使得它可以表現出另一個物件的行為,

還有其他的諸如++--等運算子,在定義特定型別的類時,提供合適的運算子函式能使我們的類更簡潔、好用,

總結

總的來說,類是一個資料管理器,建構式控制資料生成,來源可以使其他型別,也可以是相同型別,用相同型別生成新資料的時候,有復制和移動兩種選擇,復制建構式控制相同型別的資料共享行為,其主要目標就是實作兩個型別在建構式完成那一刻,在記憶體中的資料是完全一致的,移動建構式的目標則是將現有的資料轉移到當前構造的物件上來,然后使現有的資料失效,從而達到減少物件創建、銷毀,增加記憶體利用率的目的,除此之外,還能使用成員函式改變或者訪問資料,最終在解構式中結束資料的生命,此外友元類或者友元函式也是一種資料訪問途徑,
具體類的主要矛盾是資料,設計類的關鍵還是要弄清資料流向,資料自身在內部能有什么狀態,能實作什么行為,是成員函式該完成的作業,此外還要考慮相同型別相互構造時資料的共享情況,是完全隔離,還是相互影響,這些都是應該考慮的問題,畢竟確保資料從創建到銷毀的可靠性和有效性是一個具體類應該完成的基本功能,

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

標籤:其他

上一篇:【python基礎】類-模塊

下一篇:返回列表

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

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 現代C++學習指南-具體類

    > 類作為C++中重要的概念之一,有著眾多的特性,也是最迷人的部分! 類是一個加工廠,開發者使用C++提供的各種材料組裝這個工廠,使得它可以生產出符合自己要求的資料,通過對工廠的改造,可以精細控制物件從出生到死亡的各種行為,真正達到我的代碼我做主的境界。 ### 類 我們經常說的面向物件三大特征:封 ......

    uj5u.com 2023-06-22 07:41:49 more
  • 【python基礎】類-模塊

    隨著不斷給類添加功能,檔案可能變得很長,即便妥善地使用了繼承亦是如此,為遵循Python的總體理念,應讓檔案盡可能簡潔。為在這方面提供幫助,Python允許將類存盤在模塊中,然后在主程式中匯入所需的模塊。 # 1.匯入單個類 新建一個Animal類的模塊,其中只包含Animal類,撰寫程式如下所示: ......

    uj5u.com 2023-06-22 07:41:39 more
  • 54基于java的高校圖書館座位預約系統設計與實作

    基于java的座位預約系統,可以用于圖書館占位系統,圖書館座位預約系統,大學自習室占座系統,自習室座位預約系統,圖書館預約占座系統,自習室預約占座系統,高校圖書館座位預約系統等等; ......

    uj5u.com 2023-06-22 07:41:06 more
  • 【python基礎】類-繼承

    撰寫類時,并非總是要從空白開始。如果要撰寫的類時另一個現成類的特殊版本,可使用繼承。一個類繼承另一個類時,它將自動獲得另一個類的所有屬性和方法 原有的類稱為父類,而新類被稱為子類。子類繼承了其父類的所有屬性和方法,同時還可以定義自己的屬性和方法。 繼承語法格式: class 子類名(父類名): # ......

    uj5u.com 2023-06-22 07:40:41 more
  • Spring Boot 呼叫外部介面的 3 種方式,還有誰不會?!

    ## 1、簡介 SpringBoot不僅繼承了Spring框架原有的優秀特性,而且還通過簡化配置來進一步簡化了Spring應用的整個搭建和開發程序。 在Spring-Boot專案開發中,存在著本模塊的代碼需要訪問外面模塊介面,或外部url鏈接的需求, 比如在apaas開發程序中需要封裝介面在介面中調 ......

    uj5u.com 2023-06-22 07:40:32 more
  • 逍遙自在學C語言 | 指標函式與函式指標

    ## 前言 在C語言中,指標函式和函式指標是強大且常用的工具。它們允許我們以更靈活的方式處理函式和資料,進而擴展程式的功能。 本文將介紹指標函式和函式指標的概念,并講解一些常見的應用示例。 ## 一、人物簡介 - 第一位閃亮登場,有請今后會一直教我們C語言的老師 —— 自在。 ![](https:/ ......

    uj5u.com 2023-06-22 07:40:21 more
  • 53基于java的資源博客論壇系統設計與實作

    基于java的資源博客論壇系統設計與實作,可適用于java個人博客系統,個人資源博客管理系統,java博客系統,java論壇系統,類似于交友微博,新浪微博,發表動態,筆記博客,個人筆記系統。 ......

    uj5u.com 2023-06-22 07:39:52 more
  • 基于Redis實作查找附近的人/排行榜

    引言 在日常使用的有些APP中,想什么微信,百度地圖,可以可以搜尋附近的人,距離自己多遠,以及在地圖上我們可以搜索附近的某個地點,距離自己的位置。針對這種類似的功能,我們可以通過redis就能實作。 redis在3.2版本之后也提供了地理位置的能力,使用redis可以輕松實作查找附近的人 一:附近的 ......

    uj5u.com 2023-06-22 07:39:24 more
  • keycloak~CountDownLatch在keycloak中的使用

    # 概念 在Java中,`CountDownLatch`是一個執行緒同步的輔助類,用于等待其他執行緒完成操作。如果`CountDownLatch`實體被丟失或無法訪問,可能會導致無法正常使用該物件。這可能會導致等待執行緒永遠處于等待狀態,無法繼續執行。 如果意外丟失了`CountDownLatch`物件, ......

    uj5u.com 2023-06-22 07:39:07 more
  • 通用密鑰,無需密碼,在無密碼元年實作Passkeys通用密鑰登錄(基于D

    毋庸諱言,密碼是極其偉大的發明,但拜病毒和黑客所賜,一旦密碼泄露,我們就得絞盡腦汁再想另外一個密碼,但記憶力并不是一個靠譜的東西,一旦遺忘密碼,也會造成嚴重的后果,2023年業界巨頭Google已經率先支持了Passkeys登錄方式,只須在設備上利用PIN碼解鎖、指紋或面部辨識等生物識別方式,即可驗 ......

    uj5u.com 2023-06-22 07:38:57 more