(Boolan) C++面向?qū)ο蟾呒壘幊蹋ㄒ唬?/h1>

感謝侯捷老師的悉心講授的課程,讓我在對很多東西上有了更深層次的認(rèn)識茶凳。

我呢,是一個非計算機(jī)專業(yè)畢業(yè)的本科生,畢業(yè)后帶著對程序感興趣的后知后覺開始學(xué)習(xí)編程砸民,也不是抱著以工作的目的導(dǎo)向去的,學(xué)的比較雜,也缺乏系統(tǒng)性桩了。算算日子,距離第一行java代碼已經(jīng)過去兩年有余了夕土,對于飛CS的我來說馆衔,堅持到今天也算不易瘟判。但是用了這么就的“面向?qū)ο缶幊獭保约浩鋵嵅荒芴f清其本質(zhì)到底為何物角溃。這也算是我正規(guī)劃的第一步吧拷获,再次感謝Boolan網(wǎng)和侯捷老師。那么我也就來簡單的分享一下我所學(xué)到的知識吧减细,畢竟非專業(yè)出身匆瓜,如果其中有錯誤的地方,希望大家能夠指出來未蝌,謝謝大家驮吱。

Class是怎么來的

對于面向?qū)ο笳Z言來說可能很重要的任務(wù)就是和class打交道吧(至少我接觸的java、c++萧吠、python都是和class打交道的)左冬,但是在C語言中卻沒有見到過這個東西,最多也就有struct而已纸型。

其實class對于認(rèn)識世界來說是更加一致的拇砰,比如我們通常會把生物劃分為動物、植物狰腌、微生物除破,把動物又劃分為哺乳類、兩棲類等等琼腔。我們在認(rèn)識世界的時候往往會把具體的事物瑰枫,比如貓、狗展姐、人等抽象看待躁垛,找出其共性,再把不同點加入到他們自己的屬性中去圾笨,就形成了“界門綱目科屬種”這樣的生物學(xué)劃分規(guī)律教馆。所以,也就是說擂达,類和類之間應(yīng)該有關(guān)系(比如人和貓都屬于哺乳類動物)土铺,那么這些關(guān)系之間會有一些想通的屬性(比如,人和貓都喝奶長大板鬓,都會運(yùn)動等等)悲敷。但,不同種類也具有特殊的屬性俭令,比如貓有毛后德,人就沒有等等。
而軟件也應(yīng)該對現(xiàn)實事物的一種抽象表現(xiàn)形式的描述抄腔,那么類就可以很好的把各種屬性進(jìn)行隔離并描述不同類之間的關(guān)系瓢湃。比如理张,人和貓都具備喝奶的屬性,但貓具備豐富的毛發(fā)绵患,而人卻不具備這個屬性雾叭。因此,C++中使用class來隔離部分?jǐn)?shù)據(jù)落蝙,將不同的數(shù)據(jù)分隔開來织狐。同樣,針對不同的屬性筏勒,也就應(yīng)該具有針對這個屬性的響應(yīng)操作方法(成員函數(shù))移迫,比如,貓濃密毛發(fā)這個屬性奏寨,那么他就具備“舔毛”的這個操作毛發(fā)的方法(函數(shù))起意,人沒有濃密的毛發(fā)則就不需要這個函數(shù)了。

因此病瞳,C++相較于C增加重要的概念class揽咕,用這個概念來讓程序能夠使用更加抽象的方式(屬性+操作屬性的函數(shù)(方法))來描述這個世界。

什么是面向?qū)ο螅∣bject Oriented)

其實無論Java還是C++的編程過程中套菜,最重要的需要設(shè)計各種各樣的class亲善,對于Java來說,C++的class要復(fù)雜一些逗柴,C++ class可以分為“帶有指針成員變量的的class”和“不帶指針變量的class”蛹头。而,對于每次設(shè)計出來的單一class來說戏溺,這就屬于一種“基于對象(Object Based)”的編程渣蜗。

如果再拿剛才我說的人和貓來看,對于我們需要抽象一個class來描述這個類別的時候旷祸,我們這個過程耕拷,其實就是基于對象(Object Based)的過程,比如為了描述貓咪托享,而建立了一個class貓咪骚烧。如果為了實現(xiàn)某一個復(fù)雜的過程,我們往往設(shè)計一個class是不夠的闰围。比如我們養(yǎng)貓的過程來說吧赃绊,在構(gòu)造這個人和貓的系統(tǒng)的時候,顯然需要class人羡榴,也需要class貓咪碧查,這兩種class之間從抽象的角度來看是不是有一些共通之處呢?如果說吃的不一樣我們在這里先不談校仑,那么喝的水總歸是一樣的吧么夫,呼吸的空氣總歸也是一樣的吧者冤,如果為了描述人和貓分別獨立設(shè)計兩個class,也許并沒有這個必要档痪,所以,再進(jìn)一步抽象的時候邢滑,我們也許會得到(這只是為了描述這個過程腐螟,不一定非常貼切,誰讓我養(yǎng)貓呢困后,低頭抬頭看到的全是貓)一個class 動物乐纸,這時候把水和空氣作為一種通用屬性放在動物類中,而進(jìn)一步設(shè)計class貓和class人的關(guān)系時摇予,就只需要通過class動物這個類來描述他們倆之間的關(guān)系了比如對我來說一定class人里面少不了鏟貓砂汽绢,擼貓等等這一類特有的函數(shù)(方法);class貓中存在搗亂侧戴、賣萌這類特有的函數(shù)了宁昭。而喝水、吃飯酗宋、呼吸积仗、睡覺(貓一般一天能睡十八九個小時,真羨慕他們蜕猫,有吃有喝有睡寂曹,而我必須掙錢養(yǎng)他們。回右。隆圆。。好像說著說著class人中又多了一個方法翔烁。渺氧。。)這類方法(函數(shù))雖然動物類就有租漂,但是人和貓畢竟都還是有區(qū)別阶女,這時候又可以通過覆蓋這些方法來表示共性中的不同點。

因此哩治,面向?qū)ο笙噍^于面向過程來說秃踩,就是進(jìn)一步對數(shù)據(jù)和操作方法的抽象,通過進(jìn)一步的抽象來描述多個class之間的關(guān)系的抽象方法业筏。

C++程序的基本形式

說了那么多關(guān)于基于對象和面向?qū)ο蟮墓适裸狙睿敲碈++程序到底是由什么東西構(gòu)成呢

  • C++程序可以分類兩種:.cpp(C++文件)和.h(頭文件)

    而頭文件往往也分為兩部分,一部分為class的聲明(Classes Declaration)蒜胖,另外一部分則為標(biāo)準(zhǔn)庫(Standard Library)消别,其中標(biāo)準(zhǔn)庫部分里面包含了大量的算法抛蚤,可以讓我們在設(shè)計類的時候不需要重復(fù)造輪子。

  • 那么.cpp和.h如何關(guān)聯(lián)在一起呢寻狂?

    是通過#include來引入標(biāo)準(zhǔn)庫或這頭文件岁经。其中如果是引入標(biāo)準(zhǔn)庫的部分,使用的是<>來引入蛇券,系統(tǒng)中的標(biāo)準(zhǔn)庫文件缀壤,比如#include <iostream.h>。如果引入的是C語言的標(biāo)準(zhǔn)庫纠亚,可以使用cname或者name.h的方式引入塘慕,比如#include <stdio.h>或這#include <cstdio>;

如果是自己所編寫的頭文件需要使用""來引入進(jìn)來蒂胞,比如#include "complex.h"图呢,一般情況下,這個表示的是和cpp文件在同一個目錄下的.h文件骗随,如果.h文件在cpp文件目錄的某個文件夾中蛤织,需要使用#include "/dir/xxx.h"來引入了。

  • 對于C和C++的輸出有什么區(qū)別呢蚊锹?

  • C++

#include <iostream>

int main()
{
    int i = 7;
    std::cout << "i= " << i << endl;
    return 0;
}
  • C語言
  #include <stdio.h>
  int main()
  {
      int i = 7;
      printf("i=%d \n", i);
      return 0;
  }
  • 頭文件編寫的防御式聲明

    #ifndef __COMPLEX__
    #define __COMPLEX__  //防御式的聲明
    .........
    #endif
    
    • 目的:

      1. 可以讓使用者更加自由的include這個頭文件
      2. 防止同一個程序中重復(fù)的導(dǎo)入這個頭文件
    • 頭文件的布局

       #ifndef __COMPLEX__
       #define __COMPLEX__
       //前置聲明(forward declarations)
       class ostream;
       class complex;
      
       complex& __doapl(complex* ths, const complex& r);
       
       //類-聲明(class declarations)
       class complex
       {
          ....
       };
      
       //類-定義
       complex::function ....
       #endif
      
  • 以complex類(復(fù)數(shù)類)舉例說明類-聲明的定義

      class complex      //class head
      {                           //class body
        public:      //訪問級別access level為public的部分可以被外部直接訪問的部分
            complex (double r = 0, double i = 0)
                : re(r), im(i)
             {   }
             //complex () : re(0), im(0) {  }    //構(gòu)造函數(shù)的重載瞳筏,但是由于有參數(shù)的函數(shù)有默認(rèn)值,所以不能共同存在
             complex& operator += (const complex&);  //有些函數(shù)在body之外定義
             double real() const { return re; }  //有些函數(shù)再次直接定義
             double imag() const { return im; }
             void  imag(double i){ im = i; }      //函數(shù)的重載
        private:    //訪問級別access level為private的部分只能被class內(nèi)部和friend的函數(shù)直接訪問
            double re, im;    //數(shù)據(jù)應(yīng)該放在private里面牡昆,以達(dá)到封裝的效果
      
            friend complex& __doapl(complex* ths, const complex& r);    
      }
    
  • inline(內(nèi)聯(lián))函數(shù)

    • 在類本體內(nèi)所定義的函數(shù)
      例如(之前定義的class):
      double imag() const { return im; }
    • 不在本體內(nèi)定義的函數(shù)姚炕,使用inline關(guān)鍵字修飾的函數(shù)(是否能成為inline函數(shù)具體情況需要由編譯器來決定,屬于對編譯器的建議)
      例如:
      inline double imag(const complex& x)
      {
          return x.imag();
      }
      
  • 構(gòu)造函數(shù)(Constructor)

    complex (double r = 0, double i = 0)    //默認(rèn)實參
       : re(r), im(i)      //初始列丢烘,構(gòu)造函數(shù)專有的設(shè)置參數(shù)初值的方法柱宦,效率比直接賦值要高
       {   }
    complex () : re(0), im(0) {  }    //構(gòu)造函數(shù)的重載
    
    • 構(gòu)造函數(shù)會在創(chuàng)建對象的時候被自動調(diào)用

    • 函數(shù)名和類型相同,并且無返回值

    • 如果創(chuàng)建對象時沒有傳遞參數(shù)播瞳,會調(diào)用默認(rèn)參數(shù)的構(gòu)造函數(shù)

    • 使用初始列設(shè)置初值的效率高于在函數(shù)體中賦值的過程

    • 構(gòu)造函數(shù)可以重載(overloading)

    • 構(gòu)造函數(shù)可以放在private中掸刊,作為私有的,可以作為singleton的設(shè)計模式(內(nèi)存中只有一個對象)

      //singleton
      class A{
        public:
        static A& getInstance();
        setup(){.........}
        private:
        A();
        A(const A& rhs);
        ....
      };
      
      A& A::getInstance()
      {
       static A a;
       return a;
      }
      
  • 常量成員函數(shù) double real() const {return re;}

    • 對于不改變數(shù)據(jù)的函數(shù)赢乓,應(yīng)該添加const關(guān)鍵字
    • 如果不添加const關(guān)鍵字忧侧,則使用者創(chuàng)建一個常量c1const complex c1(2, 1)會報錯
  • 參數(shù)傳遞:pass by value vs. pass by reference (to const)

    • pass by value:將數(shù)據(jù)打包整體傳傳遞過去(如果對象比較大,會是效率降低)
    • pass by reference:引用在底部為指針牌芋,傳遞效率相當(dāng)于傳遞指針
      • 盡量傳遞引用蚓炬,而不要傳遞值
      • 傳遞引用被修改,則原始值也被修改
      • 如果為了提高效率躺屁,但不希望原始內(nèi)容被修改肯夏,則應(yīng)該使用const修飾
        complex& operator += (const complex& x)
  • 返回值傳遞:return by value vs. return by reference (to const)

    • 返回值盡量使用return by reference

    • 如果返回的結(jié)果實在函數(shù)中創(chuàng)建的,則不能以reference返回,因為隨著函數(shù)結(jié)束而結(jié)束驯击,不能以reference返回烁兰,否則會獲取已被銷毀的對象

    • 傳遞著無需知道接收者是以reference的形式接收

       inline complex& __doapl(complex* ths, const complex& r)
        {
            ....
            return *ths;//返回值要求為reference,則此處返回實際內(nèi)容即可
            //傳遞著無需知道接收者是以reference的形式接收
        }
      
  • 友元(friend)

    • 對于被friend修飾的函數(shù)徊都,可以直接取得private中的成員

    • 相同class的各個object互為友元(friend)

        //定義
        class complex
        {
          public:
            complex(double r = 0, double i = 0):re(r), im(i){}
            int func (const complex& param){return param.re + param.im}
          private:
            double re, im;
        }
      
        {
          //調(diào)用
          complex c1(2, 1);
          complex c2;
          c2.func(c1);  //可以直接訪問c1中的成員(相同class的不同對象互為友元)
        }
      
  • 操作符重載(c2 += c1;)

    • 成員函數(shù)類型
      • 二元操作符沪斟,具有兩個操作數(shù),系統(tǒng)會將操作符作用在左邊身上暇矫,如果左邊操作數(shù)有定義币喧,系統(tǒng)能夠找到對應(yīng)的操作符重載
      • 對于成員函數(shù)類型的操作符重載,編譯器在編譯時會為該函數(shù)自動添加this指針袱耽,該this指針就相當(dāng)于操作符左側(cè)的操作數(shù),所以在定義函數(shù)時并不需要傳入兩個參數(shù)干发,只需要傳入右側(cè)的操作數(shù)即可
        • 例如

            c2 += c1;//操作符作用在c2上
          
        • 定義方法

            inline complex& complex::operator += (const complex& r)
            {
                return __doapl(this, r);
                //返回值的設(shè)計要求主要是為了滿足鏈?zhǔn)秸{(diào)用的情況
                //返回值可以滿足這樣的要求:c3 += c2 += c1;
                //過程是c2 += c1先運(yùn)算朱巨,然后產(chǎn)生返回值,再和c3運(yùn)算
            }
            //實際上函數(shù)會被編譯器添加this指針
            //complex::operator+= (this, const complex& r)
            //其中c2 += c1;調(diào)用時枉长,相當(dāng)于將c2以this的身份傳入冀续,c1以另外的參數(shù)傳入
          
    • 非成員函數(shù)類型(無this)
      • 由于是非成員函數(shù),則編譯器并不能幫助函數(shù)添加this指針必峰,則則參數(shù)列表中洪唐,需要兩個形式參數(shù),分別來表示操作符左右兩側(cè)的操作數(shù)
        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));
            //此處生成了新的復(fù)數(shù)對象吼蚁,輸入內(nèi)部變量凭需,所以返回值不能是reference
        }
        //為了方便例如7+c1的情況,所以不講該函數(shù)設(shè)計為成員函數(shù)肝匆,而是使用全局函數(shù)來定義
      
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末粒蜈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子旗国,更是在濱河造成了極大的恐慌枯怖,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件能曾,死亡現(xiàn)場離奇詭異度硝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寿冕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門蕊程,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚂斤,你說我怎么就攤上這事存捺。” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵捌治,是天一觀的道長岗钩。 經(jīng)常有香客問我,道長肖油,這世上最難降的妖魔是什么兼吓? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮森枪,結(jié)果婚禮上视搏,老公的妹妹穿的比我還像新娘。我一直安慰自己县袱,他們只是感情好浑娜,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著式散,像睡著了一般筋遭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上暴拄,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天漓滔,我揣著相機(jī)與錄音,去河邊找鬼乖篷。 笑死响驴,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的撕蔼。 我是一名探鬼主播豁鲤,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罕邀!你這毒婦竟也來了畅形?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诉探,失蹤者是張志新(化名)和其女友劉穎日熬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肾胯,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡竖席,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了敬肚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毕荐。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖艳馒,靈堂內(nèi)的尸體忽然破棺而出憎亚,到底是詐尸還是另有隱情员寇,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布第美,位于F島的核電站蝶锋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏什往。R本人自食惡果不足惜扳缕,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望别威。 院中可真熱鬧躯舔,春花似錦、人聲如沸省古。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豺妓。三九已至飒赃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間科侈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工炒事, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留臀栈,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓挠乳,卻偏偏與公主長得像权薯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子睡扬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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