Boolan/C++面向?qū)ο蟾呒?jí)編程 part2

C++面向?qū)ο蟾呒?jí)編程 part2

@(boolan C++)[C++]
2017-10-22 14:17:56 / helingchao


概述

本章節(jié)內(nèi)容主要講述如何設(shè)計(jì)class with pointer畴博,以string為例涉瘾。

#ifndef __MYSTRING__
#define __MYSTRING__

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;
};

#include <cstring>

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}

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

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;
}

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

#include <iostream>
using namespace std;

ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

#endif


big three

所謂big three即:

  1. 拷貝構(gòu)造
  2. 拷貝賦值
  3. 析構(gòu)

1. 編譯器提供的默認(rèn)函數(shù)

聲明一個(gè)空類

聲明一個(gè)空類,如下:

class Empty {
}

C++會(huì)為上面定義的Empty類,提供默認(rèn)的成員出革。效果等同于如下定義:

class Empty {
public:
Empty() {...};
~Empty(){...};
Empty(const Empty& rhs){...};
Empty& operatpr = (const Empty& rhs) {...};
}


C++提供的默認(rèn)函數(shù)

  • default 構(gòu)造函數(shù)
  • copy構(gòu)造函數(shù)
  • 析構(gòu)函數(shù)
  • copy assignment函數(shù)

原則 01: C++默認(rèn)提供的函數(shù)僅在被調(diào)用時(shí),編譯器才會(huì)創(chuàng)建它們渡讼。
注意:這四個(gè)函數(shù)都是public和inline的骂束。


默認(rèn)函數(shù)的行為都是什么

default構(gòu)造和析構(gòu)函數(shù)

default 構(gòu)造函數(shù)和析構(gòu)函數(shù)主要是給編譯器一個(gè)地方放置“藏身幕后”的代碼。

  • default構(gòu)造函數(shù) :調(diào)用base classesnon-static 成員變量的構(gòu)造函數(shù)成箫。
  • 析構(gòu)函數(shù) :調(diào)用base classesnon-static 成員變量的析構(gòu)函數(shù)展箱。

注意: non-static成員的說(shuō)法,static 類成員不在default構(gòu)造函數(shù)的初始化范圍內(nèi)蹬昌。

copy構(gòu)造函數(shù)和copy assignment

單純的將對(duì)象的每一個(gè)non-static成員拷貝到目標(biāo)對(duì)象混驰。

用戶需要重新定義copy構(gòu)造函數(shù)和copy assignment的場(chǎng)景

類中包含以下類型成員

  • 引用類型
  • 指針類型
  • const類型

2. 字符串設(shè)計(jì)

1509260994792.png
  1. 用指針保存存儲(chǔ)數(shù)據(jù)的地址,不用數(shù)組皂贩。好處在于靈活的存儲(chǔ)栖榨,無(wú)需考慮設(shè)計(jì)多大的數(shù)組。

實(shí)際是一種動(dòng)態(tài)存儲(chǔ)思想與靜態(tài)存儲(chǔ)思想之間的決策明刷。

3. ctor & dtor

inline string::string(const char* cstr= 0) {
    if (cstr) {
        m_data = new char[strlen(cstr)+1];
        strcpy(m_data,cstr);
    }
    else {
        m_data = new char[1];
        m_data[0] = '\0';
    }
}

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

字符串的兩種形式:

  1. 串+‘\0’
  2. 長(zhǎng)度字段+串

4. copy ctor & copy op =

1509261365517.png

淺拷貝 vs. 深拷貝

在copy對(duì)象時(shí)僅copy指針成員屬于淺copy, 創(chuàng)建新的內(nèi)存并將指針的內(nèi)容copy到新內(nèi)存是深copy婴栽。

在class with pointer 默認(rèn)的copy ctor & copy op = 使用的是淺拷貝。

淺拷貝造成的問(wèn)題:

淺拷貝會(huì)造成 alias(別名) 和 memory leak

alias 與 野指針/懸空指針

單一個(gè)內(nèi)存單元被多個(gè)對(duì)象所只向時(shí)辈末,可以看作是該內(nèi)存單元存在了別名愚争。

// p_a 與p_b 構(gòu)成了alias 
int *p_a = new int();
int *p_b = p_a;

alias引入的問(wèn)題:
內(nèi)存單元被釋放時(shí),其他地點(diǎn)的別名可能不知道該內(nèi)存以被釋放挤聘,繼而繼續(xù)使用該內(nèi)存轰枝,產(chǎn)生不確定的行為(undefined behavior)

1509262248771.png

什么是懸空指針(dangling pointer)?

If a pointer still references the original memory after it has been freed, it is called a dangling pointer.

懸空指針是指針最初指向的內(nèi)存已經(jīng)被釋放了的一種指針组去。

什么是野指針(wild pointer)?

A pointer in c which has not been initialized is known as wild pointer.

野指針(wild pointer)就是沒(méi)有被初始化過(guò)的指針.

5. 拷貝賦值/copy assignment operator

string& string::operator = (const string& str_r) {
    if (this == &str_r) {  // 自我檢測(cè)
        return *this;
    }

    delete[] m_data;
    m_data = new char[strlen(str_r.m_data) + 1];
    strcpy(m_data, str_r.m_data);

    return *this;
}

注意??:
拷貝賦值中的自我檢測(cè)

copy op=的動(dòng)作:

  1. 清空已有的數(shù)據(jù)
  2. 創(chuàng)建新內(nèi)存
  3. 拷貝

拷貝構(gòu)造與拷貝賦值的差別

  1. 拷貝構(gòu)造是創(chuàng)建新對(duì)象鞍陨,拷貝已有對(duì)象到新對(duì)象
  2. 拷貝賦值時(shí),兩個(gè)對(duì)象都已經(jīng)被創(chuàng)建添怔。

基于上述兩點(diǎn)拷貝構(gòu)造無(wú)需檢測(cè)自我賦值湾戳,但拷貝賦值需要贤旷。


內(nèi)存管理

1. stack vs. heap

1509263493997.png

stack, 是存在于某個(gè)作用域的一塊內(nèi)存空間砾脑。 例如函數(shù)被調(diào)用時(shí)幼驶,函數(shù)本身就會(huì)生成一個(gè)stack。

heap韧衣,是指由操作系統(tǒng)提供的一塊gloabl內(nèi)存空間盅藻,可由程序員動(dòng)態(tài)創(chuàng)建。

2. static object & global object

兩者在生命周期都是在main結(jié)束之后畅铭,程序結(jié)束之后才結(jié)束氏淑。

3. new: 先創(chuàng)建內(nèi)存,后調(diào)用ctor

1509262367694.png

new的三個(gè)步驟

// 原始語(yǔ)句
complex* pc = new complex(1,2);
// 編譯器內(nèi)部轉(zhuǎn)換后的遇見(jiàn)
void* mem = opreator new(sizeof(complex));  // 1. 分配內(nèi)存
pc = static_cast<complex*>(mem);  // 2. 類型轉(zhuǎn)化
pc->complex::complex(1,2);  // 3. 調(diào)用構(gòu)造函數(shù)

成員函數(shù)的調(diào)用過(guò)程

哪個(gè)對(duì)象調(diào)用類成員函數(shù)硕噩,(編譯器)默認(rèn)將該對(duì)象的指針傳給被調(diào)用成員函數(shù)this假残。

pc->complex::complex(1,2);

complex::complex(pc,1,2);

3. delete:先調(diào)用dtor, 后釋放內(nèi)存

1509262410676.png

4. array new 一定要搭配 array delete

1509262539128.png

擴(kuò)展補(bǔ)充:類模版..

1. C++對(duì)象內(nèi)存模型

  1. non-static 數(shù)據(jù)成員
  2. static 數(shù)據(jù)成員
  3. non-static 成員函數(shù)
  4. static 成員函數(shù)
1509263831824.png
  1. static 數(shù)據(jù)成員/static成員函數(shù)/none -static成員函數(shù) 全局只有一份。
  2. none-static數(shù)據(jù)成員每個(gè)對(duì)象各有一份

this指針

哪個(gè)對(duì)象調(diào)用成員函數(shù)炉擅,哪個(gè)對(duì)象的指針就會(huì)作為參數(shù)傳遞給成員函數(shù)的this指針

complex c1;
c1.real();
complex::real(&c1);
  1. none-static 成員函數(shù)通過(guò)this指針將處理不同對(duì)象的non-static數(shù)據(jù)辉懒。
  2. this pointer如何傳遞:non-static 成員函數(shù)是全局唯一的,哪個(gè)對(duì)象調(diào)用ns成員函數(shù)就將哪個(gè)對(duì)象的地址作為this指針傳遞給ns成員函數(shù)
1509262669674.png

static 成員

static成員脫離于對(duì)象谍失。成員函數(shù)也是脫離于對(duì)象眶俩。

  1. static 成員函數(shù)沒(méi)有this pointer
  2. st 成員函數(shù)只能處理 st數(shù)據(jù)
  3. st成員函數(shù)沒(méi)有this指針?biāo)圆荒芴幚矸莝t數(shù)據(jù)

靜態(tài)數(shù)據(jù)要在classbody外定義,定義時(shí)不要添加static聲明快鱼。

class acount{
    static int a;
}

int acount::a;  // 類st成員定義
  1. st 成員數(shù)據(jù)要在class body 外“定義”颠印。這里是定義,因?yàn)橐峙鋬?nèi)存抹竹。
  2. static 成員函數(shù)的兩種調(diào)用方式:object調(diào)用线罕,classname 調(diào)用。

設(shè)計(jì)static成員的原則

如果數(shù)據(jù)是在對(duì)象間通用的柒莉,則將該數(shù)據(jù)設(shè)計(jì)為類的static成員闻坚。

static 版本的singleton

class singleton {
public:
    static singleton& get_instance() {
        static singleton a;
        return a;
    }
private:
    singleton() {};
    
}

cout

1509263864546.png

class template

1509263880945.png

function template

1509263907947.png

argument deduction (實(shí)參推導(dǎo)):

  1. argument deduction (實(shí)參推導(dǎo)):不同于class template , function template 在使用時(shí)不用指定具體類型

名稱空間

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兢孝,一起剝皮案震驚了整個(gè)濱河市窿凤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌跨蟹,老刑警劉巖雳殊,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異窗轩,居然都是意外死亡夯秃,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仓洼,“玉大人介陶,你說(shuō)我怎么就攤上這事∩ǎ” “怎么了哺呜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)箕戳。 經(jīng)常有香客問(wèn)我某残,道長(zhǎng),這世上最難降的妖魔是什么陵吸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任玻墅,我火速辦了婚禮,結(jié)果婚禮上壮虫,老公的妹妹穿的比我還像新娘澳厢。我一直安慰自己,他們只是感情好旨指,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布赏酥。 她就那樣靜靜地躺著,像睡著了一般谆构。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上框都,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天搬素,我揣著相機(jī)與錄音,去河邊找鬼魏保。 笑死熬尺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谓罗。 我是一名探鬼主播粱哼,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼檩咱!你這毒婦竟也來(lái)了揭措?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤刻蚯,失蹤者是張志新(化名)和其女友劉穎绊含,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體炊汹,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躬充,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片充甚。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡以政,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伴找,到底是詐尸還是另有隱情妙蔗,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布疆瑰,位于F島的核電站眉反,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏穆役。R本人自食惡果不足惜寸五,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耿币。 院中可真熱鬧梳杏,春花似錦、人聲如沸淹接。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)塑悼。三九已至劲适,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厢蒜,已是汗流浹背霞势。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斑鸦,地道東北人愕贡。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像巷屿,于是被迫代替她去往敵國(guó)和親固以。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,516評(píng)論 1 51
  • Classes的兩個(gè)經(jīng)典分類 Class without pointer member(s) complex Cl...
    Wancho閱讀 342評(píng)論 0 0
  • 307嘱巾、setValue:forKey和setObject:forKey的區(qū)別是什么憨琳? 答:1, setObjec...
    AlanGe閱讀 1,547評(píng)論 0 1
  • 一個(gè)博客,這個(gè)博客記錄了他讀這本書(shū)的筆記浓冒,總結(jié)得不錯(cuò)栽渴。《深度探索C++對(duì)象模型》筆記匯總 1. C++對(duì)象模型與內(nèi)...
    Mr希靈閱讀 5,584評(píng)論 0 13
  • 朋友們看我把感悟日記寫(xiě)得不亦樂(lè)乎稳懒,又開(kāi)始寫(xiě)隨筆闲擦,而且把碼字描述得那么美好慢味,估計(jì)也想躍躍欲試了吧。 我在朋友圈是這樣...
    莉穎心苑閱讀 443評(píng)論 0 0