閉關多日整理一份C++中那些重要又容易忽視的細節

      網友投稿 894 2022-05-30

      @[toc]

      基礎篇

      喜歡用內聯函數嗎?

      內聯函數,都知道是什么嘛,就不多解釋了,用這個開頭,因為它夠簡單,又有足夠的爭議性。

      有的人喜歡用內聯函數,有的人不喜歡用,我嘛,無所謂,什么時候想起來就什么時候用,或者在代碼審計的時候會去調整一部分函數為內聯函數。

      內聯函數是C++為了提高程序運行速度所做的一項改進,讓我們深入到函數內部,了解一下內聯函數和常規函數的區別。

      在C當中,是沒有inline這個關鍵字的,C要使用類似的功能,就需要去寫宏函數了,但是又不好寫,并不是誰都能駕馭的了的。

      C++在編譯的時候,會將每個函數編譯成一條條機器語言指令,在執行常規函數時,程序將會跳轉到相應的地址,將參數復制到堆棧,跳到標記函數起點的內存單元,執行函數代碼,并在函數結束時返回。

      這反復橫跳并記錄過程的過程,是要有一定的開銷的。

      內聯函數則提供了另一種可能,對于內聯函數,編譯器在編譯的時候直接在調用處將函數展開,嵌入到調用函數中,所以無需反復橫跳,減少了時間的開銷,但是,增加了空間的開銷。

      應有選擇的使用內聯函數,因為它節省下來的時間確實是少得可憐,如果說執行函數代碼的時間比函數調用機制的時間長,那用內聯函數就沒什么意思。

      所以才會產生這么一個說法:在某個短小精悍的函數被多次調用時,才考慮將其轉為內聯函數,蒼蠅肉,實在小,不過聚沙成塔嘛。

      頭文件與名空間,好用吧!

      名空間的支持是一項C++特性,旨在讓我們比阿尼寫大型程序以及將多個廠商的現有代碼組合起來的程序時更容易。

      注意:假設名空間和聲明區域定義了相同的名稱,試圖使用聲明將名空間的名稱導入該聲明區域,則兩個名稱會發生沖突,從而出錯。如果使用using編譯指令將該名空間的名稱導入該聲明區域,則局部版本將隱藏名空間版本。

      一般說來,using聲明(要用什么就聲明什么)比使用using編譯指令(using namespace XXX)更安全,這是由于它只導入指定的名稱,如果該名稱與局部名稱發生沖突,那你還導入它干嘛?

      沒用過,下次可以試試自己寫一個名空間,如果是沒有名字的名空間,那么只能在包含那個名空間的文件里面使用該名空間內部的內容,類似于,靜態變量、函數的集合。

      引用

      首先,&不是地址運算符,而是類型標識符的一部分,就像聲明中的char*是指向char的指針一樣,int&是指向int的引用。

      示例:

      int a; int &b = a;

      上述引用聲明允許將a和b互換,因為它們指向相同的值和內存單元。

      不過呢,必須在聲明引用變量的時候進行初始化:

      int a; int &b; b = a; //這樣是不行的

      返回引用的高效性

      傳統的返回機制是這樣的:

      1、獲取返回值

      2、將返回值復制到一個臨時位置

      3、調用函數從臨時位置獲取這個值

      返回引用的返回機制是這樣的:

      1、獲取返回值

      2、直接將返回值拷貝給調用函數

      如果返回值不大,那就不大,如果返回值是一個結構這種比較大的東西,那就比較麻煩了,能明白我意思不?

      返回引用時,應避免返回函數終止時不再存在的內存單元引用(在指針里說過同樣的話)。

      為避免這種問題,最簡單的方法就是:返回一個作為參數傳遞給函數的引用。

      何時使用引用參數?

      想用的時候唄。

      閉關多日,整理一份C++中那些重要又容易忽視的細節

      使用引用參數這種“大招”的主要動機有:

      1、程序員能夠修改調用函數中的數據對象

      2、可以提高程序的運行速度。

      那么,==什么時候該使用指針,什么時候該使用引用,什么時候該使用按值傳遞呢==?

      對象數據很小,按值傳遞即可。 對象是數組,指針。這是唯一的選擇,并將指針聲明為指向const的指針。 數據對象是較大的結構,使用const指針或const引用,提高程序效率。 數據對象是類對象,使用const引用。類設計的語義常常要求使用引用,因此,在傳遞類對象參數的標準方式是按引用傳遞。 對于修改調用函數中數據的函數: 如果數據對象是內置數據類型,使用指針。 如果對象是數組,只能使用指針。 如果對象是結構,使用指針或引用都可以。 如果對象是類對象,使用引用。

      控制對成員的訪問,是公有?是私有?

      對新手來說,這個點估計是經常被忽略的吧。

      數據項通常放在私有部分,組成類接口的成員函數放在公有部分。

      為什么呢?這是C++的封裝性。不然要類干什么?結構體不能用嗎?

      在后面講設計模式的時候還會再細講這一部分。

      ==插點題外話==

      昨天我們老師給我們講了意味深長的一段話。

      現在你們年輕人不是很喜歡講“內卷”嘛,然后用什么去對抗內卷,“躺平”嘛。

      “用友”聽說過嗎?低代碼聽說過嗎?

      未來,這些前篇一律的基本代碼,已經并不局限與本科生,專科生也可以做,甚至高中生都可以做。而某些本科生,還高人一等的姿態。

      其實他講低代碼的時候,我想起來了QT的UI,只要你會拖控件,就可以做出界面來,代碼可以后臺自動生成。

      而現在又有多少人,是面向百度編程的。

      未來是低代碼的時代,只會寫低代碼的人只會越來越卷,直到找不到工作。

      所以不要把過多的時間花在那些低意義的學習上。

      本科階段,真正應該花時間去研究的,是算法,是操作系統,是數據庫,是網絡編程,是計網,是英語,等等這些東西。

      不要以為你們是大數據專業的,真正有大數據的公司,會把數據給你嗎?

      這才是我心目中真正==人間清醒==的老師。

      寫給目前困惑的朋友,這篇的內容可能一周后你就不記得了,但是希望這段話對你有幫助吧。

      運算符重載

      C++允許將運算符重載擴展到用戶定義的類型,重載運算符可以使代碼看起來更自然。

      要重載運算符,需要使用被稱為運算符函數的特殊函數形式:

      operator(argument-list)

      下面的實例使用成員函數演示了運算符重載的概念:

      #include using namespace std; class Box { public: // 重載 + 運算符,用于把兩個 Box 對象相加 Box operator+(const Box& b) { Box box; box.length = this->length + b.length; box.breadth = this->breadth + b.breadth; box.height = this->height + b.height; return box; } private: double length; // 長度 double breadth; // 寬度 double height; // 高度 };

      可重載運算符:

      面試題:C++類自動提供的成員函數

      默認構造函數:如果沒有定義構造函數 默認析構函數:如果沒有定義 復制構造函數:、、、、 賦值運算符:、、、、 地址運算符:、、、、

      當時面試的時候突然碰到這個問題,有感而發。

      虛基類為什么需要虛析構函數?

      直接來個示例看一下吧:

      class test{ public: virtual ~test() = 0; // 聲明一個純虛析構函數 };

      ==防止內存泄露==,定義一個基類的指針p,在delete p時,如果基類的析構函數是虛函數,這時==只會看p所賦值的對象==,如果p賦值的對象是派生類的對象,就會調用派生類的析構函數(毫無疑問,在這之前也會先調用基類的構造函數,在調用派生類的構造函數,然后調用派生類的析構函數,基類的析構函數,所謂先構造的后釋放);如果p賦值的對象是基類的對象,就會調用基類的析構函數,這樣就不會造成內存泄露。

      如果基類的析構函數不是虛函數,在delete p時,調用析構函數時,==只會看指針的數據類型==,而不會去看賦值的對象,這樣就會造成內存泄露。

      虛函數的工作原理

      通常,編譯器處理虛函數的方法是:給每個對象添加一個隱藏成員。隱藏成員中保存一個指向函數地址數組的指針。

      這種數組稱為虛函數表(virtual function table, vtbl)。

      虛函數表中存儲了為對象進行聲明的虛函數的地址。

      例如,基類對象包含一個指針,該指針指向基類中所有虛函數的地址表。派生類對象包含一個指向獨立地址表的指針。如果派生類提供了虛函數的新定義,該函數表將保存新函數的地址;如果派生類沒有重新定義虛函數,該vtbl將保存函數原始版本的地址。如果派生類定義了新的虛函數,則該函數也將被添加到vtbl中。注意,無論類中包含的虛函數是1個還是10個,都只需要在對象中添加1個地址成員,只是表的大小不同而已。

      調用虛函數時,程序將查看存儲在對象中的vtbl地址,然后轉向相應的函數地址表。如果使用類聲明中定義的第一個虛函數,則程序將使用數組中中的第一個函數地址,并執行具有該地址的函數。如果使用類聲明中定義的第三個函數,程序將使用地址為數組中第三個元素的函數。

      簡而言之,使用虛函數時,在內存和執行速度方面有一定的成本,包括:

      1)每個對象都將增大,增大量為存儲函數地址表(數組)的空間。 2)對每個類,編譯器都創建一個虛函數地址表(數組)。 3)每個函數調用都需要執行一部額外的操作,即到表中查找地址。

      雖然非虛函數的效率比虛函數稍高,但不具備動態聯編(Dynimac Blinding)的功能。

      友元

      以前看到這個模塊兒都是直接劃走,根本沒興趣。

      但是,這幾天嘗試著了解了一下友元(主要是有幾個大佬反復的跟我說過,友元,要用),我發現,學會友元,能讓我對C++的認識更進一步。所以我來了。

      了解一下友元函數吧

      友元函數是可以直接訪問類的私有成員的非成員函數。它是定義在類外的普通函數,它不屬于任何類,但需要在類的定義中加以聲明,聲明時只需在友元的名稱前加上關鍵字friend,其格式如下:

      friend 類型 函數名(形式參數);

      友元函數的聲明可以放在類的私有部分,也可以放在公有部分,它們是沒有區別的,都說明是該類的一個友元函數。 一個函數可以是多個類的友元函數,只需要在各個類中分別聲明。 友元函數的調用與一般函數的調用方式和原理一致。

      友元函數雖然不是類成員卻能夠訪問類的所有成員的函數。類授予它的友元特別的訪問權。通常同一個開發者會出于技術和非技術的原因,控制類的友元和成員函數(否則當你想更新你的類時,還要征得其它部分的擁有者的同意)。

      來個使用示例看一下:

      #include "iostream" using namespace std; class Point { int aa; public: friend void bb(Point cc); Point() { aa=88; } }; void bb(Point cc) { int d=cc.aa; //通過對象的引用可以直接訪問 cout<<"這是友元函數通過對象的引用直接訪問私有變量的例子!"<

      友元函數是否破壞了類的封裝性

      至于它是否破壞了類的封裝性,這個不同的人有不同的說法啦,認為它沒有破壞封裝性的人覺得只有類聲明可以控制哪些函數可以訪問內部數據。

      仁者見仁,智者見智吧。

      我看到一段比較好的解答:

      我們已知道類具有封裝和信息隱藏的特性。只有類的成員函數才能訪問類的私有成員,程序中的其他函數是無法訪問私有成員的。非成員函數可以訪問類中的公有成員,但是如果將數據成員都定義為公有的,這又破壞了隱藏的特性。另外,應該看到在某些情況下,特別是在對某些成員函數多次調用時,由于參數傳遞,類型檢查和安全性檢查等都需要時間開銷,而影響程序的運行效率。

      為了解決上述問題,提出一種使用友元的方案。友元是一種定義在類外部的普通函數,但它需要在類體內進行說明,為了與該類的成員函數加以區別,在說明時前面加以關鍵字friend。友元不是成員函數,但是它可以訪問類中的私有成員。友元的作用在于提高程序的運行效率,但是,它破壞了類的封裝性和隱藏性,使得非成員函數可以訪問類的私有成員。

      友元可以是一個函數,該函數被稱為友元函數;友元也可以是一個類,該類被稱為友元類。

      什么時候使用友元函數:

      1)運算符重載的某些場合需要使用友元。 2)兩個類要共享數據的時候

      略顯疲憊呀

      C++

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:思寒漫談測試人職業發展
      下一篇:醫院網絡安全架構的探索和改進 | 最佳實踐
      相關文章
      亚洲av区一区二区三| 亚洲三级在线视频| 亚洲乱码无限2021芒果| 久久亚洲AV成人出白浆无码国产| 国产亚洲av片在线观看16女人| 亚洲综合色在线观看亚洲| 处破女第一次亚洲18分钟| 亚洲欧美中文日韩视频| 亚洲中文字幕无码av永久| 成人区精品一区二区不卡亚洲| 亚洲午夜国产精品无卡| 亚洲国产精品成人久久久| 亚洲性一级理论片在线观看| 亚洲成人网在线观看| 亚洲一区在线免费观看| 亚洲乱码中文论理电影| 亚洲人成网国产最新在线| 亚洲欧洲AV无码专区| 国产精品亚洲天堂| 精品亚洲成A人在线观看青青| 亚洲 自拍 另类小说综合图区| 亚洲v国产v天堂a无码久久| 亚洲情侣偷拍精品| 亚洲熟妇无码乱子AV电影| 亚洲人成网站在线播放vr| 亚洲av鲁丝一区二区三区| 亚洲蜜芽在线精品一区| 亚洲乱码日产精品BD在线观看| 亚洲人成自拍网站在线观看| 国产精品亚洲小说专区| 狠狠综合久久综合88亚洲| 亚洲va久久久噜噜噜久久狠狠| 亚洲日韩在线第一页| 久久久青草青青国产亚洲免观 | 久久久久亚洲AV综合波多野结衣| 国产亚洲精品无码拍拍拍色欲| 亚洲深深色噜噜狠狠爱网站| 亚洲AV日韩AV永久无码下载| 亚洲综合亚洲国产尤物| 国产AV旡码专区亚洲AV苍井空| 亚洲国产成人久久一区二区三区 |