色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

以良好的方式編寫C++ class

Linux愛好者 ? 來源:博客園 ? 作者:melonstreet ? 2022-06-29 14:07 ? 次閱讀

以良好的方式編寫C++ class

假設現在我們要實現一個復數類complex,在類的實現過程中探索良好的編程習慣。

① Header(頭文件)中的防衛式聲明

complex.h:
#ifndef__COMPLEX__
#define__COMPLEX__
classcomplex
{

}
#endif

防止頭文件的內容被多次包含。

② 把數據放在private聲明下,提供接口訪問數據

#ifndef__COMPLEX__
#define__COMPLEX__
classcomplex
{
public:
doublereal()const{returnre;}
doubleimag()const{returnim;}
private:
doubelre,im;
}
#endif

③ 不會改變類屬性(數據成員)的成員函數,全部加上const聲明

例如上面的成員函數:

doublereal()`const`{returnre;}
doubleimag()`const`{returnim;}

既然函數不會改變對象,那么就如實說明,編譯器能幫你確保函數的const屬性,閱讀代碼的人也明確你的意圖。

而且,const對象才可以調用這些函數——const對象不能夠調用非const成員函數。

④ 使用構造函數初始值列表

classcomplex
{
public:
complex(doubler=0,doublei=0)
:re(r),im(i){}
private:
doubelre,im;
}

在初始值列表中,才是初始化。在構造函數體內的,叫做賦值。

⑤如果可以,參數盡量使用reference to const

為complex 類添加一個+=操作符:

classcomplex
{
public:
complex&operator+=(constcomplex&)
}

使用引用避免類對象構造與析構的開銷,使用const確保參數不會被改變。內置類型的值傳遞與引用傳遞效率沒有多大差別,甚至值傳遞效率會更高。

例如,傳遞char類型時,值傳遞只需傳遞一個字節;引用實際上是指針實現,需要四個字節(32位機)的傳遞開銷。但是為了一致,不妨統一使用引用。

⑥ 如果可以,函數返回值也盡量使用引用

以引用方式返回函數局部變量會引發程序未定義行為,離開函數作用域局部變量被銷毀,引用該變量沒有意義。但是我要說的是,如果可以,函數應該返回引用。

當然,要放回的變量要有一定限制:該變量的在進入函數前,已經被分配了內存。以此條件來考量,很容易決定是否要放回引用。而在函數被調用時才創建出來的對象,一定不能返回引用。

說回operator +=,其返回值就是引用,原因在于,執行a+=b時,a已經在內存上存在了。

operator + ,其返回值不能是引用,因為a+b的值,在調用operator +的時候才產生。

下面是operator+= 與’operator +’ 的實現:

inlinecomplex&complex::operator+=(constcomplex&r)
{
this->re+=r->re;
this->im+=r->im;
return*this;
}
inlinecomplexoperator+(constcomplex&x,constcomplex&y)
{
returncomplex(real(x)+real(y),//新創建的對象,不能返回引用
imag(x)+imag(y));
}

operator +=中返回引用還是必要的,這樣可以使用連續的操作:

c3+=c2+=c1;

⑦ 如果重載了操作符,就考慮是否需要多個重載

就我們的復數類來說,+可以有多種使用方式:

complexc1(2,1);
complexc2;
c2=c1+c2;
c2=c1+5;
c2=7+c1;

為了應付怎么多種加法,+需要有如下三種重載:

inlinecomplexoperator+(constcomplex&x,constcomplex&y)
{
returncomplex(real(x)+real(y),
imag(x+imag(y););
}
inlinecomplexoperator+(constcomplex&x,doubley)
{
returncomplex(real(x)+y,imag(x));

inlinecomplexoperator+(doublex,constcomplex&y)
{
returncomplex(x+real(y),imag(y));
}

⑧ 提供給外界使用的接口,放在類聲明的最前面

這是某次面試中,面試官大哥告訴我的。想想確實是有道理,類的用戶用起來也舒服,一眼就能看見接口。

Class with pointer member(s):記得寫Big Three

C++的類可以分為帶指針數據成員與不帶指針數據成員兩類,complex就屬于不帶指針成員的類。而這里要說的字符串類String,一般的實現會帶有一個char *指針。帶指針數據成員的類,需要自己實現class三大件:拷貝構造函數、拷貝賦值函數、析構函數。

classString
{
public:
String(constchar*cstr=0);
String(constString&str);
String&operator=(constString&str);
~String();
char*get_c_str()const{returnm_data};
private:
char*m_data;
}

如果沒有寫拷貝構造函數、賦值構造函數、析構函數,編譯器默認會給我們寫一套。然而帶指針的類不能依賴編譯器的默認實現——這涉及到資源的釋放、深拷貝與淺拷貝的問題。在實現String類的過程中我們來闡述這些問題。

①析構函數釋放動態分配的內存資源

如果class里有指針,多半是需要進行內存動態分配(例如String),析構函數必須負責在對象生命結束時釋放掉動態申請來的內存,否則就造成了內存泄露。

局部對象在離開函數作用域時,對象析構函數被自動調用,而使用new動態分配的對象,也需要顯式的使用delete來刪除對象。而delete實際上會調用對象的析構函數,我們必須在析構函數中完成釋放指針m_data所申請的內存。下面是一個構造函數,體現了m_data的動態內存申請:

/*String的構造函數*/
inline
String::String(constchar*cstr=0)
{
if(cstr)
{
m_data=newchar[strlen(cstr)+1];//這里,m_data申請了內存
strcpy(m_data,cstr);
}
else
{
m_data=newchar[1];
*m_data='';
}
}

這個構造函數以C風格字符串為參數,當執行

String*p=newString("hello");

m_data向系統申請了一塊內存存放字符串hello

e4d49818-f75f-11ec-ba43-dac502259ad0.png

析構函數必須負責把這段動態申請來的內存釋放掉:

inline
String::~String()
{
delete[]m_data;
}

②賦值構造函數與復制構造函數負責進行深拷貝

來看看如果使用編譯器為String默認生成的拷貝構造函數與賦值操作符會發生什么事情。默認的復制構造函數或賦值操作符所做的事情是對類的內存進行按位的拷貝,也稱為淺拷貝,它們只是把對象內存上的每一個bit復制到另一個對象上去,在String中就只是復制了指針,而不復制指針所指內容。現在有兩個String對象:

Stringa("Hello");
Stringb("World");

a、b在內存上如圖所示:

e4f4a0d6-f75f-11ec-ba43-dac502259ad0.png

如果此時執行

b=a;

淺拷貝體現為:

e5013936-f75f-11ec-ba43-dac502259ad0.png

存儲World的內存塊沒有指針所指向,已經成了一塊無法利用內存,從而發生了內存泄露。不止如此,如果此時對象a被刪除,使用我們上面所寫的析構函數,存儲Hello的內存塊就被釋放調用,此時b.m_data成了一個野指針。

來看看我們自己實現的構造函數是如何解決這個問題的,它復制的是指針所指的內存內容,這稱為深拷貝

/*拷貝賦值函數*/
inlineString&String::operator=(constString&str)
{
if(this==&str)//①
return*this;
delete[]m_data;//②
m_data=newchar[strlen(str.m_data)+1];//③
strcpy(m_data,str.m_data);//④
return*this
}

這是拷貝賦值函數的經典實現,要點在于:

① 處理自我賦值,如果不存在自我賦值問題,繼續下列步驟:② 釋放自身已經申請的內存③ 申請一塊大小與目標字符串一樣大的內存④ 進行字符串的拷貝

對于a = b,②③④過程如下:

e50d80c4-f75f-11ec-ba43-dac502259ad0.pnge5193e50-f75f-11ec-ba43-dac502259ad0.pnge5230dae-f75f-11ec-ba43-dac502259ad0.png

同樣的,復制構造函數也是一個深拷貝的過程:

inlineString::String(constString&str)
{
m_data=newchar[strlen(str)+1];
strcpy(m_data,str.m_data);
}

另外,一定要在operator = 中檢查是否self assignment 假設這時候確實執行了對象的自我賦值,左右pointers指向同一個內存塊,前面的步驟②delete掉該內存塊造成下面的結果。當企圖對rhs的內存進行訪問是,結果是未定義的。

e52c144e-f75f-11ec-ba43-dac502259ad0.png

static與類

① 不和對象直接相關的數據,聲明為static

想象有一個銀行賬戶的類,每個人都可以開銀行賬戶。存在銀行利率這個成員變量,它不應該屬于對象,而應該屬于銀行這個類,由所有的用戶來共享。

static修飾成員變量時,該成員變量放在程序的全局區中,整個程序運行過程中只有該成員變量的一份副本。而普通的成員變量存在每個對象的內存中,若把銀行利率放在每個對象中,是浪費了內存。

② static成員函數沒有this指針

static成員函數與普通函數一樣,都是只有一份函數的副本,存儲在進程的代碼段上。不一樣的是,static成員函數沒有this指針,所以它不能夠調用普通的成員變量,只能調用static成員變量。普通成員函數的調用需要通過對象來調用,編譯器會把對象取地址,作為this指針的實參傳遞給成員函數:

obj.func()--->Class::fun(&obj);

而static成員函數即可以通過對象來調用,也可以通過類名稱來調用。

③在類的外部定義static成員變量

另一個問題是static成員變量的定義。static成員變量必須在類外部進行定義:

classA
{
private:
staticinta;//①
}
intA::a=10;//②

注意①是聲明,②才是定義,定義為變量分配了內存。

④static與類的一些小應用

這些可以用來應付一下面試,在實現單例模式的時候,static成員函數與static成員變量得到了使用,下面是一種稱為”餓漢式“的單例模式的實現:

classA
{
public:
staticA&getInstance();
setup(){...};
private:
A();
A(constA&rhs);
staticAa;
}

這里把class A的構造函數都設置為私有,不允許用戶代碼創建對象。要獲取對象實例需要通過接口getInstance。”餓漢式“缺點在于無論有沒有代碼需要aa都被創建出來。下面是改進的單例模式,稱為”懶漢式“:

classA
{
public:
staticA&getInstance();
setup(){....};
private:
A();
A(constA&rsh);
...
};
A&A::getInstance()
{
staticAa;
returna;
}

“懶漢式”只有在真正需要a時,調用getInstance才創建出唯一實例。這可以看成一個具有拖延癥的單例模式,不到最后關頭不干活。很多設計都體現了這種拖延的思想,比如string的寫時復制,真正需要的時候才分配內存給string對象管理的字符串。

原文標題:漫談 C++:良好的編程習慣與編程要點

文章出處:【微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4328

    瀏覽量

    62574
  • C++
    C++
    +關注

    關注

    22

    文章

    2108

    瀏覽量

    73623
  • Class
    +關注

    關注

    0

    文章

    53

    瀏覽量

    19724
  • CONST
    +關注

    關注

    0

    文章

    44

    瀏覽量

    8159

原文標題:漫談 C++:良好的編程習慣與編程要點

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    匯編語言模塊調用C++函數實例

    現在編寫一個簡單的應用程序,提示用戶輸入整數,通過移位的方式將其與 2 的幕 (21?2?) 相乘,并用填充前導空格的形式再次顯示每個乘積。輸入-輸出使用 C++。匯編模塊將調用 3 個 C+
    發表于 10-11 09:52 ?927次閱讀

    C語言實現面向對象的方式 C++中的class的運行原理

    這里主要介紹下在C語言中是如何實現的面向對象。知道了C語言實現面向對象的方式,再聯想下,C++中的class的運行原理是什么?
    發表于 10-21 09:00 ?1131次閱讀

    如何用C++編寫流水燈程序?

    為什么很少用C++開發單片機?如何用C++編寫流水燈程序?
    發表于 09-30 08:27

    C++ Class library and Automati

    This file has two distinct features: A complete C++ class library (source code) that gives access
    發表于 08-08 21:48 ?9次下載

    C++課件、習題及答案

    *1.1  從CC++*1.2  最簡單的C++程序 1.3  C++程序的構成和書寫形式 1.4 
    發表于 09-08 09:35 ?108次下載
    <b class='flag-5'>C++</b>課件、習題及答案

    異常安全的C++代碼編寫

    關于C++中異常的爭論何其多也,但往往是一些不合事實的誤解。異常曾經是一個難以用好的語言特性,幸運的是,隨著C++社區經驗的積累,今天我們已經有足夠的知識輕松編寫
    發表于 09-16 11:50 ?5次下載

    C++程序設計教程之C++的初步知識的詳細資料說明

    C++程序設計教程之C++的初步知識的詳細資料說明包括了:1. 從CC++,2 . 最簡單的C++程序,3 .
    發表于 03-14 14:48 ?31次下載
    <b class='flag-5'>C++</b>程序設計教程之<b class='flag-5'>C++</b>的初步知識的詳細資料說明

    使用C語言和C++編寫俄羅斯方塊的資料和源代碼免費下載

    本文檔的主要內容詳細介紹的是使用C語言和C++編寫俄羅斯方塊的資料和源代碼免費下載。
    發表于 06-10 08:00 ?4次下載
    使用<b class='flag-5'>C</b>語言和<b class='flag-5'>C++</b><b class='flag-5'>編寫</b>俄羅斯方塊的資料和源代碼免費下載

    使用C++編寫的2048小游戲的論文和源代碼免費下載

    本文檔的主要內容詳細介紹的是使用C++編寫的2048小游戲的論文和源代碼免費下載。
    發表于 07-01 10:26 ?18次下載
    使用<b class='flag-5'>C++</b><b class='flag-5'>編寫</b>的2048小游戲的論文和源代碼免費下載

    如何基于Keil、STM32用C++編寫流水燈程序?

    通常來說,在單片機上編程,要么匯編,要么C語言,而用C++進行開發的很少,那么究竟能不能用C++開發單片機呢? 答案肯定是可以的,下面講講基于Keil、STM32,用C++
    的頭像 發表于 04-30 16:10 ?3111次閱讀

    C++ STM32 編程 005 用c++編寫STM32程序的準備

    ? ? ? ? 由于我們使用的是 ARM 的工具鏈 是gcc的,所以,我們大可以用c++編寫程序,無論是 c++99 或c++11 還是 c
    發表于 12-02 14:36 ?5次下載
    <b class='flag-5'>C++</b> STM32 編程 005 用<b class='flag-5'>c++</b><b class='flag-5'>編寫</b>STM32程序的準備

    C++中struct和class的區別?

    C++中struct和class的區別是什么?C++中struct和class的最大區別在于: ? ? ? ? struct的成員默認是公有的, 而
    的頭像 發表于 03-10 17:41 ?758次閱讀

    CC++編寫環境下LabVIEW如何調用動態庫?

    C語言編寫的動態鏈接庫相比,不同的地方在于extern int “C” __declspec(dllexport) add(int x,int y) 這一導出語句,在C代碼中沒有”
    發表于 06-11 09:15 ?7735次閱讀
    <b class='flag-5'>C</b>和<b class='flag-5'>C++</b><b class='flag-5'>編寫</b>環境下LabVIEW如何調用動態庫?

    使用C++編寫通用庫并在 Rust 中使用它 (WASI)

    使用 C++ 編寫通用庫并在 Rust 中使用它 (WASI) WebAssembly 簡介 WebAssembly 是一種二進制指令格式,旨在成為一種低級虛擬機,可以在 Web 瀏覽器中接近本機
    的頭像 發表于 06-16 10:03 ?1085次閱讀
    使用<b class='flag-5'>C++</b><b class='flag-5'>編寫</b>通用庫并在 Rust 中使用它 (WASI)

    c++入門后如何進階

    C++11 是下一個 C++ 標準,但我們通常稱之為現代 C++。現代 C++ 也包括了 C++14 和
    發表于 07-21 08:56 ?342次閱讀
    <b class='flag-5'>c++</b>入門后如何進階
    主站蜘蛛池模板: 手机在线免费| 2022国产91精品久久久久久| 99在线观看精品| 国产一区二区高清| 强行撕开衣服捏胸黄文| 伊人久久中文| 国产精品亚洲视频在线观看| 欧美性类s0x| 中文字幕完整高清版| 国产精品一库二库三库| 青柠在线观看视频在线| 中文字幕在线观看国产| 韩国精品韩国专区久久| 天天澡夜夜澡人人澡| av先锋影音资源男人站| 乱叫抽搐流白浆免费视频| 亚洲AV怡红院AV男人的天堂| 二级毛片免费观看全程| 尿了么app| 2023极品少妇XXXO露脸| 精品一区二区三区高清免费观看| 无码国产成人777爽死| 成 人 色综合| 男生插曲女生身全过程| 中国字字幕在线播放2019| 极品虎白在线观看| 亚洲国产在线视频精品| 国产精品乱码色情一区二区视频| 日本高清不卡码无码v亚洲| 99久久国产露脸精品竹菊传煤| 久久九九日本韩国精品| 亚洲在线中文无码首页| 国内精品蜜汁乔依琳视频 | 久久免费精品一区二区| 亚洲精品AV无码永久无码| 国产精品爽爽久久久久久蜜桃| 色内射无码AV| 丰满老熟好大bbbxxx| 色婷婷狠狠97成为人免费| 成人毛片18岁女人毛片免费看| 奇米色偷偷|