亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現(xiàn)在的位置是:首頁 > 技術(shù)閱讀 >  C++編程習(xí)慣與編程要點

C++編程習(xí)慣與編程要點

時間:2024-02-12

來源:CPP開發(fā)前沿


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

假設(shè)現(xiàn)在我們要實現(xiàn)一個復(fù)數(shù)類complex,在類的實現(xiàn)過程中探索良好的編程習(xí)慣。

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

complex.h:

# ifndef  __COMPLEX__
# define __COMPLEX__
class complex
{

}
# endif

防止頭文件的內(nèi)容被多次包含。

② 把數(shù)據(jù)放在private聲明下,提供接口訪問數(shù)據(jù)

# ifndef  __COMPLEX__
# define __COMPLEX__
class complex
{
public:
double real() const {return re;}
double imag() const {return im;}
private:
doubel re,im;
}
# endif

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

例如上面的成員函數(shù):

double real () `const` {return re;}
double imag() `const` {return im;}

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

而且,const對象才可以調(diào)用這些函數(shù)——const對象不能夠調(diào)用非const成員函數(shù)。

④ 使用構(gòu)造函數(shù)初始值列表

class complex
{
public:
complex(double r = 0, double i =0)
: re(r), im(i) { }
private:
doubel re,im;
}

在初始值列表中,才是初始化。在構(gòu)造函數(shù)體內(nèi)的,叫做賦值。

⑤如果可以,參數(shù)盡量使用reference to const

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

class complex
{
public:
complex& operator += (const complex &)
}

使用引用避免類對象構(gòu)造與析構(gòu)的開銷,使用const確保參數(shù)不會被改變。內(nèi)置類型的值傳遞與引用傳遞效率沒有多大差別,甚至值傳遞效率會更高。例如,傳遞char類型時,值傳遞只需傳遞一個字節(jié);引用實際上是指針實現(xiàn),需要四個字節(jié)(32位機)的傳遞開銷。但是為了一致,不妨統(tǒng)一使用引用。

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

以引用方式返回函數(shù)局部變量會引發(fā)程序未定義行為,離開函數(shù)作用域局部變量被銷毀,引用該變量沒有意義。但是我要說的是,如果可以,函數(shù)應(yīng)該返回引用。當然,要放回的變量要有一定限制:該變量的在進入函數(shù)前,已經(jīng)被分配了內(nèi)存。以此條件來考量,很容易決定是否要放回引用。而在函數(shù)被調(diào)用時才創(chuàng)建出來的對象,一定不能返回引用。

說回operator +=,其返回值就是引用,原因在于,執(zhí)行a+=b時,a已經(jīng)在內(nèi)存上存在了。

operator + ,其返回值不能是引用,因為a+b的值,在調(diào)用operator +的時候才產(chǎn)生。

下面是operator+= 與’operator +’ 的實現(xiàn):

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

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

c3 += c2 += c1;

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

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

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

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

inline complex operator+ (const complex & x ,const complex & y)
{
return complex (real(x)+real(y),
imag(x+imag(y););
}
inline complex operator + (const complex & x, double y)
{
return complex (real(x)+y,imag(x));

inline complex operator + (double x,const complex &y)
{
return complex (x+real(y),imag(y));
}

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

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

Class with pointer member(s):記得寫B(tài)ig Three

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

class String
{
public:
String (const char * cstr = 0);
String (const String & str);
String & operator = (const String & str);
~String();
char * get_c_str() const {return m_data};
private:
char * m_data;
}

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

①析構(gòu)函數(shù)釋放動態(tài)分配的內(nèi)存資源

如果class里有指針,多半是需要進行內(nèi)存動態(tài)分配(例如String),析構(gòu)函數(shù)必須負責(zé)在對象生命結(jié)束時釋放掉動態(tài)申請來的內(nèi)存,否則就造成了內(nèi)存泄露。局部對象在離開函數(shù)作用域時,對象析構(gòu)函數(shù)被自動調(diào)用,而使用new動態(tài)分配的對象,也需要顯式的使用delete來刪除對象。而delete實際上會調(diào)用對象的析構(gòu)函數(shù),我們必須在析構(gòu)函數(shù)中完成釋放指針m_data所申請的內(nèi)存。下面是一個構(gòu)造函數(shù),體現(xiàn)了m_data的動態(tài)內(nèi)存申請:

/*String的構(gòu)造函數(shù)*/
inline
String ::String (const char *cstr = 0)
{
if(cstr)
{
m_data = new char[strlen(cstr)+1]; // 這里,m_data申請了內(nèi)存
strcpy(m_data,cstr);
}
else
{
m_data= new char[1];
*m_data = '\0';
}
}

這個構(gòu)造函數(shù)以C風(fēng)格字符串為參數(shù),當執(zhí)行

String *p = new String ("hello");

m_data向系統(tǒng)申請了一塊內(nèi)存存放字符串hello

析構(gòu)函數(shù)必須負責(zé)把這段動態(tài)申請來的內(nèi)存釋放掉:

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

②賦值構(gòu)造函數(shù)與復(fù)制構(gòu)造函數(shù)負責(zé)進行深拷貝

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

String a("Hello");
String b("World");

a、b在內(nèi)存上如圖所示:

如果此時執(zhí)行

b = a;

淺拷貝體現(xiàn)為:

存儲World\0的內(nèi)存塊沒有指針所指向,已經(jīng)成了一塊無法利用內(nèi)存,從而發(fā)生了內(nèi)存泄露。不止如此,如果此時對象a被刪除,使用我們上面所寫的析構(gòu)函數(shù),存儲Hello\0的內(nèi)存塊就被釋放調(diào)用,此時b.m_data成了一個野指針。來看看我們自己實現(xiàn)的構(gòu)造函數(shù)是如何解決這個問題的,它復(fù)制的是指針所指的內(nèi)存內(nèi)容,這稱為深拷貝

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

這是拷貝賦值函數(shù)的經(jīng)典實現(xiàn),要點在于:

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

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

同樣的,復(fù)制構(gòu)造函數(shù)也是一個深拷貝的過程:

inline String ::String(const String & str )
{
m_data = new char[ strlen (str) +1];
strcpy(m_data,str.m_data);
}

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

static與類

① 不和對象直接相關(guān)的數(shù)據(jù),聲明為static

想象有一個銀行賬戶的類,每個人都可以開銀行賬戶。存在銀行利率這個成員變量,它不應(yīng)該屬于對象,而應(yīng)該屬于銀行這個類,由所有的用戶來共享。static修飾成員變量時,該成員變量放在程序的全局區(qū)中,整個程序運行過程中只有該成員變量的一份副本。而普通的成員變量存在每個對象的內(nèi)存中,若把銀行利率放在每個對象中,是浪費了內(nèi)存。

② static成員函數(shù)沒有this指針

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

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

而static成員函數(shù)即可以通過對象來調(diào)用,也可以通過類名稱來調(diào)用。

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

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

class A
{
private:
static int a; //①
}
int A::a = 10; //②

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

④static與類的一些小應(yīng)用

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

class A
{
public:
static A& getInstance();
setup(){...};
private:
A();
A(const A & rhs);
static A a;
}

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

class A
{
public:
static A& getInstance();
setup(){....};
private:
A();
A(const A& rsh);
...
};
A& A::getInstance()
{
static A a;
return a;
}

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

C++學(xué)習(xí)資料免費獲取方法:關(guān)注程序喵大人,后臺回復(fù)“程序喵”即可免費獲取40萬字C++進階獨家學(xué)習(xí)資料。





往期推薦


1、少寫點
if-else吧,它的效率有多低你知道嗎?
2、年度原創(chuàng)好文匯總
3、全網(wǎng)首發(fā)!!C++20新特性全在這一張圖里了
4
他來了,他來了,C+
+17新特性精華都在這了
5、一文讓你搞懂設(shè)計模式
6、C++11新特性,所有知識點都在這了!
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美日韩国产影片| a91a精品视频在线观看| 久久久国产精品亚洲一区| 国产精品女人毛片| 亚洲免费成人| 欧美日韩岛国| 亚洲欧美日韩国产中文在线| 欧美黑人多人双交| 国产日韩精品一区二区三区| 亚洲国产日韩欧美一区二区三区| 久久国产成人| 一区二区三区免费看| 国产亚洲人成网站在线观看| 亚洲一区二区综合| 韩国美女久久| 欧美激情一区| 欧美一级夜夜爽| 狠狠色丁香久久综合频道| 久久精品日产第一区二区| 国产精品毛片高清在线完整版| 麻豆国产精品va在线观看不卡| 亚洲国产一区二区三区a毛片| 国产精品毛片在线看| 麻豆精品在线观看| 久久夜色精品一区| 小辣椒精品导航| 亚洲精品久久久久| 国产精品理论片| 久久久噜噜噜| 欧美承认网站| 国产精品久久久久久影院8一贰佰 国产精品久久久久久影视 | 亚洲国产岛国毛片在线| 国产亚洲福利社区一区| 欧美视频一区在线| 欧美激情第4页| 亚洲免费成人av| 亚洲人成绝费网站色www| 亚洲美女免费精品视频在线观看| 亚洲国产精品va在线看黑人动漫| 国产精品亚洲人在线观看| 欧美日韩国产区一| 久久综合中文字幕| 久久久精品999| 亚洲一区二区三区视频| 一区二区高清| 老司机一区二区三区| 欧美精品一区二区三区久久久竹菊| 免费观看欧美在线视频的网站| 久久久www成人免费精品| 亚洲一区二区视频在线观看| 午夜精品久久一牛影视| 欧美另类视频在线| 国产精品免费小视频| 激情偷拍久久| 日韩图片一区| 欧美在线观看一二区| 蜜臀91精品一区二区三区| 久久久精品久久久久| 久久看片网站| 国产一区二区三区直播精品电影| 亚洲高清三级视频| 亚洲精品在线观| 亚洲欧美另类中文字幕| 久久综合亚洲社区| 欧美国产日韩一区二区三区| 欧美高清视频在线 | 尤物yw午夜国产精品视频| 亚洲欧美成人综合| 免费久久99精品国产自在现线| 久久亚洲欧美| 欧美色图天堂网| 亚洲精品系列| 国产日产欧产精品推荐色| 亚洲视频免费| 国产精品久久综合| 一区二区三区高清不卡| 欧美精品色网| 亚洲激情精品| 香蕉精品999视频一区二区| 欧美v国产在线一区二区三区| 亚洲国产婷婷| 欧美日韩国产成人在线| 亚洲人成艺术| 可以看av的网站久久看| 国产日韩欧美综合在线| 一区二区三区精品视频| 国内自拍视频一区二区三区| 午夜一区二区三视频在线观看| 欧美不卡视频一区| 亚洲人体1000| 国产欧美日韩免费| 欧美一区二区三区免费大片| 国产亚洲一区二区三区在线观看| 亚洲精品小视频在线观看| 国产精品日韩欧美综合| 欧美激情一二三区| 欧美在线三区| 亚洲国产日韩欧美综合久久| 欧美精品亚洲精品| 一区二区三区三区在线| 国产欧美在线看| 国产欧美日韩综合一区在线播放| 美乳少妇欧美精品| 欧美一级久久久| 国产美女精品视频免费观看| 亚洲字幕在线观看| 国内精品久久久久影院色| 欧美专区日韩专区| 久久噜噜亚洲综合| 在线亚洲免费| 亚洲欧美影音先锋| 久久婷婷成人综合色| 久久精品在线播放| 欧美在线视屏| 久久久精品网| 亚洲视频视频在线| 亚洲欧美清纯在线制服| 欧美一区二区三区四区在线| 99在线精品观看| 在线免费观看日本欧美| 亚洲精品小视频在线观看| 亚洲精品视频二区| 亚洲国产一区二区三区a毛片| 国产精品入口尤物| 国产精品久久久久秋霞鲁丝| 欧美视频在线观看一区二区| 精东粉嫩av免费一区二区三区| 国产精品自在在线| 国产伦精品一区二区三区免费迷| 国产精品国产三级国产专播精品人| 久久夜色精品| 亚洲欧美韩国| 久久久久成人精品| 欧美美女福利视频| 国产精品久久久久国产a级| 国产精品久久久久99| 国产精品久久97| 狠狠色狠狠色综合日日五| 亚洲素人在线| 免费欧美日韩国产三级电影| 国产欧美日韩精品丝袜高跟鞋 | 韩国成人精品a∨在线观看| 国产美女一区| 亚洲人体影院| 欧美成人一二三| 国产日韩亚洲欧美| 亚洲激情偷拍| 久久亚洲精品一区| 国产精品大片wwwwww| 亚洲福利精品| 久久国内精品视频| 国产一区二区三区四区三区四| 在线视频你懂得一区二区三区| 久久精品亚洲| 极品尤物av久久免费看| 久久精品国产久精国产一老狼 | 亚洲国产一区二区三区青草影视| 亚洲女性裸体视频| 国产精品欧美日韩久久| 午夜久久黄色| 一区二区在线视频播放| 久久久久网址| 亚洲第一精品夜夜躁人人爽 | 久久国产99| 狠狠操狠狠色综合网| 欧美不卡一区| 久久av在线| 亚洲精品一区二区三区蜜桃久| 欧美精品一区二区在线观看| 亚洲永久免费精品| 国产精品午夜久久| 欧美成人dvd在线视频| 亚洲综合日韩| 日韩视频免费观看| 精品粉嫩aⅴ一区二区三区四区| 欧美激情精品| 久久久青草青青国产亚洲免观| 亚洲欧洲三级电影| 国内精品久久国产| 国产精品色网| 伊人久久大香线| 国产精品国产一区二区| 欧美精品在线观看播放| 国产欧美va欧美va香蕉在| 在线播放一区| 亚洲综合第一| 免费欧美电影| 午夜一区二区三区不卡视频| 久久久久久高潮国产精品视| 欧美电影免费观看大全| 国产精品五区| 一区二区三区**美女毛片| 亚洲在线观看免费视频| 亚洲一区二区三区精品视频| 国产三区精品| 一区二区在线视频播放| 亚洲电影观看| 性8sex亚洲区入口| 久久女同精品一区二区| 欧美另类综合|