亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++深入刨析類與對象的使用

 更新時間:2022年05月26日 08:53:48   作者:喬喬家的龍龍  
類和對象是兩種以計算機為載體的計算機語言的合稱。對象是對客觀事物的抽象,類是對對象的抽象。類是一種抽象的數(shù)據(jù)類型;變量就是可以變化的量,存儲在內(nèi)存中—個可以擁有在某個范圍內(nèi)的可變存儲區(qū)域

this指針

現(xiàn)在給出一段代碼,實現(xiàn)一個普通的日期 date 的打印:

class date
{
public:
	void print()
	{
		cout << year<<' ' << month <<' '<< day << endl;
	}
	void init(int y, int m, int d)
	{
		year = y;
		month = m;
		day = d;
	}
private:
	int year;
	int month;
	int day;
};
int main()
{
	date d1;
	date d2;
	date d3;
	d1.init(2022, 5, 15);
	d2.init(2022, 5, 14);
	d3.init(2022, 5, 13);
	d1.print();
	d2.print();
	d3.print();
	return 0;
}

結果如你所想:

那么問題來了,d1,d2,d3在調用類里面的 print 函數(shù)時,并沒有指明對象或者給出形參,最后結果卻能打印出不同的三個結果,這是為什么呢?、

這就是C++語法中的隱藏的 this 指針這里的 this 指針其實就是隱含的形參,這個形參會對函數(shù)進行處理,比如剛剛的 print 函數(shù)以及他的調用,他們的真面目其實是這樣:

void print(date* this)

{ cout<< this->year << ’ ’ << this->month << ’ ’ << this->day << endl; }

d1->init(&d1,2022,5,15);

也就是說所有成員變量前面都會有一個 this 指針修飾(實際上 this 指針是個 const 類型,指針不能修改但指向內(nèi)容可以修改),使得形參和實參之間架起一座無形的橋梁,進行連結。值得注意的是,這個過程是編譯器在搗鼓實現(xiàn)的,不需要我們自己去搞,要是寫的時候強行帶上 this 指針反而還會報錯。

那數(shù)據(jù)是如何對應上的呢?換個問題就是 print 每次是怎么樣對應上 d1,d2,d3的,其實訪問成員變量年月日,并不是在訪問 private 里的年月日,private 里只是聲明并不存在空間的開辟,訪問但是同一個類里面的 init 函數(shù)從而訪問到成員變量。

this指針存放在哪

this 指針存在寄存器里面!

其實編譯器在生成程序時加入了獲取對象首地址的相關代碼。并把獲取的首地址存放在了寄存器ECX中(VC++編譯器是放在ECX中,其它編譯器有可能不同)。也就是成員函數(shù)的其它參數(shù)正常都是存放在棧中,而this指針參數(shù)則是存放在寄存器中。

類的靜態(tài)成員函數(shù)因為沒有this指針這個參數(shù),所以類的靜態(tài)成員函數(shù)也就無法調用類的非靜態(tài)成員變量。

nullptr與類

如果我定義了一個空值指針,讓空值指針分別去訪問我類里面的函數(shù)與成員變量會怎么樣:

class Data
{
public:
	void print()
	{
		cout << "hello" << endl;
	}
	void printa()
	{
		cout << a << endl;
	}
private:
	int a;
};
int main()
{
	Data* n = nullptr;
	n->print();//訪問函數(shù)
	n->printa();//訪問成員變量
	return 0;
}

結果如圖:

沒錯,程序崩潰辣!但是很明顯,hello 打印出來了就說明函數(shù)的訪問是沒有問題的,但是是沒有辦法訪問成員變量的。

我們說類里面用空指針訪問函數(shù),成員變量結果會不同,原因就是函數(shù)在公共代碼區(qū),不需要解引用,直接找到函數(shù)地址變成 call 地址即可,而成員變量的訪問需要解引用自然空指針就會寄。

空指針 nullptr 其實并不是真的“空”,實際上是真實存在的,他指向虛擬進程空間里面地址為 0 的地方,這個 0 地址處是用來程序初始化的,是預留出來的,并不是用來存儲數(shù)據(jù)的。因此空指針一旦指向數(shù)據(jù),這個數(shù)據(jù)就是不被認可的,沒有意義的。

類的默認成員函數(shù)

類里面什么都沒有,就稱它為空類,實際上空類中真的什么都沒有嗎?答案是 NO!任何一個類在默認情況下都會生成 6 個成員函數(shù)。

構造函數(shù)

構造函數(shù)是特殊的成員函數(shù),需要注意的是,構造函數(shù)雖然名叫構造,但他的主要任務并不是開辟空間或者創(chuàng)建對象,而是將對象初始化。我們不寫,編譯器也會生成一個默認無參數(shù)的構造函數(shù),但這個默認的構造函數(shù)不一定有用,而 C++11打的補丁,針對編輯器自己生成的默認成員函數(shù)不初始化的問題,給了缺省值來供默認構造函數(shù)使用。

需要注意的是:

  1. 類名與函數(shù)名保持一致
  2. 可以不用傳參,沒有返回值
  3. 對象實例化時編輯器自動調用對應的構造函數(shù)
  4. 構造函數(shù)支持函數(shù)重載
  5. 如果類中沒有顯式定義構造函數(shù),C++編譯器會自動生成一個無參的默認構造函數(shù),如果我們自己顯式定義了就不會給出了
  6. 無參的構造函數(shù)和全缺省的構造函數(shù)都被稱為默認構造函數(shù),并且默認構造函數(shù)只能有一個

意義

C++將變量分為兩種:內(nèi)置類型(int,char,指針類型等等)和自定義類型(struct/class 去定義的類型對象)

而這正好就是 C++ 語法設計的一個敗筆,他會導致

如果有內(nèi)置類型的成員就得自己寫構造函數(shù),比如:

class Stack
{
public:
     void push(int x){
     }
     void pop(){
     }
private:
     Stack stackpush;
     Stack stackpop;
}

該類里面只有自定義類型成員變量,就不需要去寫構造函數(shù),默認的構造函數(shù)就可以完成了??偨Y一下就是如果類里面只有自義定類型,就可以用默認構造函數(shù),如果存在內(nèi)置類型或者需要顯示傳參初始化就需要自己寫構造函數(shù)。

析構函數(shù)

如果構造函數(shù)高速了我們對象是怎么來的,那么析構函數(shù)就是在告訴我們對象是怎么走的。析構函數(shù)與構造函數(shù)功能相反,他并不是完成了對象的銷毀,因為局部對象銷毀是由編譯器來完成,而析構函數(shù)是完成對象的一些資源清理工作,他是在對象銷毀時自動調用。

再三強調不是銷毀對象本身!不是銷毀對象本身!所謂的資源清理針對的對象是 malloc,new 或者 fopen 這類的操作進行清理收尾,其實本質上就相當于我們之前的 destroy 函數(shù)。

其特征如下:

  1. 析構函數(shù)名是在類名前面加上字符 -
  2. 無參數(shù)也無返回值
  3. 一個類有且僅有一個析構函數(shù),如果沒有顯式定義,系統(tǒng)會自動生成析構函數(shù)
  4. 對象聲明周期結束時,C++編譯系統(tǒng)自動調用析構函數(shù)

但是注意一個順序問題:

int main()
{
Stack st1;
Stack st2;
return 0;
}

st1 相比 st2 先構造這沒什么問題,但 st2 卻比 st1 先析構,析構和構造的順序是相反的。但他和構造函數(shù)一樣,對內(nèi)置類型不處理但是對于自定義類型會去調用。

拷貝構造

有沒有可能你會想搞一個和自己一樣的對象出來呢?如果想那就該我拷貝構造登場辣!

int main()
{
     Date d1(2022,5,16);
     Date d2(d1);
     return 0;
}

這里的 d2 就是拿 d1 來初始化,所以拷貝構造只有單個形參,該形參是對類類型對象的引用,一般由 const 修飾,再用已存在的類類型對象創(chuàng)建新對象時由編譯器自動調用。他實際上是構造函數(shù)的一種函數(shù)重載,他的參數(shù)只要一個,而且必須使用引用傳參,因為使用傳值會引發(fā)無窮遞歸調用。

在什么情況下系統(tǒng)會調用拷貝構造函數(shù):

(1)用類的一個對象去初始化另一個對象時

(2)當函數(shù)的形參是類的對象時(也就是值傳遞時),如果是引用傳遞則不會調用

(3)當函數(shù)的返回值是類的對象或引用時

C++規(guī)定了自義定類型對象,拷貝初始化要調用拷貝構造完成。這就引出來一個問題,比如我們拷貝棧,定義了兩個對象 st1 和 st2,假如我寫成下面的樣子就會出亂子:

Stack st1(1);
Stack st2(st1);

因為是拷貝構造, st2 指向地址和 st1 是一樣的,這并不是我們想要的結果,我們傳統(tǒng)拷貝是指向同一塊空間,而且這里拷貝構造會崩,原因很簡單,這里原理上進行的是淺拷貝,默認構造函數(shù)會對類里面內(nèi)置類型進行淺拷貝,值拷貝,對于自義定類型,編譯器不知道自義定類型的行為,如何拷貝,什么規(guī)則,像 stack 這種類型就需要深拷貝實現(xiàn),我們后面再去學習。

淺拷貝是按位拷貝對象,它會創(chuàng)建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型),拷貝的就是內(nèi)存地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象。

st1 構建完成變成 st2 參數(shù)去初始化 st2,st2 一旦拷貝完成就要進行析構,而析構會先執(zhí)行 st2 ,st2 一旦被清理這塊空間就會被銷毀,而此時 st1 還在使用這塊空間,就會導致內(nèi)存錯誤。

運算符重載

說到運算符重載,這里面有幾分門道嗷。他是個啥呢?

您可以重定義或重載大部分 C++ 內(nèi)置的運算符,這樣就能使用自定義類型的運算符。重載的運算符是帶有特殊名稱的函數(shù),函數(shù)名是由關鍵字 operator 和其后要重載的運算符符號構成的。與其他函數(shù)一樣,重載運算符有一個返回類型和一個參數(shù)列表。

說的比較玄學,其實你設想一下這個場景,假如我們給出的日期類有兩個成員 d1,d2,我們?nèi)绻ケ容^他們能用運算符 ==,<,> 來比較嗎,或者我給日期 +、- 一個數(shù)可以嗎,很明顯不行,因為內(nèi)置類型可以直接使用運算符,但是自義定類型不可以,因此就引入了我們的運算符重載。

運算符重載——函數(shù),函數(shù)名:operator +運算符,參數(shù)是運算符的操作數(shù),如下:

operator==(Date d1,Date d2)
{
      return d1.year == d2.year
      && d1.month == d2.month
      && d1.day == d2.day
}

細心的你可能會問,內(nèi)置類型我定義在私有域里面該怎么訪問呢?這就有三種方法:

  1. 從根源解決,改成公有類型public(尬活了屬于是)
  2. 再寫一個公有域的函數(shù)來調用私有域的內(nèi)置類型成員;
  3. C++ 友元(后續(xù)會學習到)

先別覺得ez,因為這里他會報錯

==是要求的兩個參數(shù),我這里也是兩個參數(shù)沒錯啊,為什么會參數(shù)太多???別忘了,操作符還有 默認的形參 this,他被限定為第一個形參,因此我們只需要寫一個參數(shù)即可:

operator==(Date d)
{
      return year == d.year
      && month == d.month
      && day == d.day
}

編譯器遇到 if(d1 == d2) 這樣的語句,就會去處理成對應的重載運算符調用 if(d1.operator(d2)),這里編譯器時很聰明的,你寫的全局他會去調用全局,你寫的成員他會去調用成員。而且遇到運算符重載他會在優(yōu)先去類里面找,沒有才回去類外面找,也就是說類的里外同時存在運算符重載函數(shù)是可以編譯過去的。

注意一下

::

sizeof

?:

.

.*

這五個操作符是不能進行重載的,在選擇題中會經(jīng)常出現(xiàn)。

到此這篇關于C++深入刨析類與對象的使用的文章就介紹到這了,更多相關C++類與對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 如何在C++類的外部調用類的私有方法

    如何在C++類的外部調用類的私有方法

    這篇文章主要介紹了如何在C++類的外部調用類的私有方法,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-09-09
  • 探討C語言的那些小秘密之斷言

    探討C語言的那些小秘密之斷言

    我盡可能的把我所理解的斷言的使用講解清楚,希望我在此所講的斷言能夠對你有所幫助,讓你以后能夠在代碼中靈活使用斷言
    2013-09-09
  • C++動態(tài)規(guī)劃實現(xiàn)查找最長公共子序列

    C++動態(tài)規(guī)劃實現(xiàn)查找最長公共子序列

    這篇文章主要介紹了C++動態(tài)規(guī)劃最長公共子序列,在動態(tài)規(guī)劃中,你要將某個指標最大化。在這個例子中,你要找出最長公共子序列
    2022-06-06
  • Qt在vs2019中使用及設置方法

    Qt在vs2019中使用及設置方法

    這篇文章主要介紹了Qt在vs2019中使用及設置方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • Qt5.9畫五角星的方法

    Qt5.9畫五角星的方法

    這篇文章主要為大家詳細介紹了Qt5.9畫五角星的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C語言實現(xiàn)經(jīng)典掃雷小游戲的示例代碼

    C語言實現(xiàn)經(jīng)典掃雷小游戲的示例代碼

    掃雷游戲是在一個指定的二維空間里,隨機布置雷,把不是雷的位置都找出來,在你點一個位置的時候它會顯示它周圍全部雷的個數(shù),根據(jù)這個線索去找 ,會更容易贏。本文將用C語言實現(xiàn)這一經(jīng)典游戲,感興趣的可以嘗試一下
    2022-11-11
  • C++實現(xiàn)將s16le的音頻流轉換為float類型

    C++實現(xiàn)將s16le的音頻流轉換為float類型

    這篇文章主要為大家詳細介紹了如何利用C++實現(xiàn)將s16le的音頻流轉換為float類型,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-04-04
  • C++處理鍵盤輸入的方法

    C++處理鍵盤輸入的方法

    這篇文章主要介紹了C++處理鍵盤輸入的方法,是C++程序設計中非常實用的技巧,需要的朋友可以參考下
    2014-10-10
  • 一文帶你吃透C++繼承

    一文帶你吃透C++繼承

    繼承是C++語言的一個重要特性,繼承使得軟件(代碼)復用變得簡單、易行,可以通過繼承復用已有的程序資源,縮短軟件開發(fā)的周期,本就帶大家吃透C++繼承,需要的朋友可以參考下
    2023-06-06
  • C++ 數(shù)字的反轉實現(xiàn)實例

    C++ 數(shù)字的反轉實現(xiàn)實例

    這篇文章主要介紹了C++ 數(shù)字的反轉實現(xiàn)實例的相關資料,需要的朋友可以參考下
    2017-06-06

最新評論