久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    向iOS開發者介紹C++(一)

     方海龍的書館 2016-02-21
    原文出處: Matt Galloway   譯文出處:cocoachina   歡迎分享原創到伯樂頭條

    你已經精通了Objective-C,并且一直想學更酷的東西?看看這篇文章吧!本文將向iOS開發者介紹C++。稍后我會介紹,Objective-C能夠無縫地使用C和C++代碼。因此,基于以下幾點原因,iOS開發者理解C++將會很有幫助:

    • 1.有時候你想在應用中使用一個用C++編寫的庫。
    • 2.你可能用C++寫一部分應用程序的代碼,以便更容易跨平臺移植。
    • 3. 了解其他語言通常能幫助你更好地理解編程。

    這篇文章針對那些已經理解Objective-C的iOS開發者。前提是假定你已明白怎么寫Objective-C代碼,并熟悉基本的C概念,比如類型、指針、函數等。

    準備好學C++了么?那么就馬上開始吧!

    開始:語言簡史

    C++和Objective-C有一些共源:它們都根植于老式的好用的C語言,都是C語言的“超集”。因此,你可以在這兩種語言中使用C語言的一些功能,和每種語言的附加特性。

    如果你熟悉Objective-C,那么你將能粗略地理解你所遇到的C++代碼。例如,兩種語言中的數值類型(int型、float型和char型)的表現方式和使用規則都是完全一樣的。

    Objective-C和C++都在C語言基礎上添加了面向對象的特征。如果你不熟悉“面向對象”,那么你真正需要明白的是面向對象指數據是由對象表示的,而對象是類的實例。事實上,C++最初稱為“C with Classes”,內在的涵義是使C++面向對象。

    “那么有什么區別么?”我聽到了你的疑問。最大的區別是面向對象特性的方法。在C++中,很多行為是發生在編譯時,而在Objective-C中,大多數是發生在運行時。你可能已經修改了Objective-C的運行時間來實現了一個類似method swizzling的詭計,而在C++中這是不可能的。

    C++也不像Objective-C一樣有大量內省以及映射方法。在C++中,沒有辦法獲得C++對象的類,而在Objective-C中你可以在一個實例中調用“類”方法。同樣的,在C++中也沒有相當于isMemberOfClass或者isKindOfClass的類。

    以上對C++的粗略介紹顯示了C++和Objective-C的歷史和主要不同點。歷史部分已經完成了,到我們繼續學習一些C++特征的時間了。

    C++ 類

    在任何面向對象語言中,首先你要知道的是如何定義一個類。在Objective-C中,你通過創建一個頭文件和一個執行文件來定義一個類,在C++中同樣如此,語法也十分相似。

    如下,是一個Objective-C類的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // MyClass.h
    #import <Foundation/Foundation.h>
    @interface MyClass : NSObject
    @end
    // MyClass.m
    #import “MyClass.h”
    @implementation MyClass
    @end

    作為一個經驗豐富的iOS開發者你應該很明白,但是看看同樣用C++寫的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // MyClass.h
    class MyClass {
    };
    // MyClass.cpp
    #include “MyClass.h”
    /* Nothing else in here */

    這里有一些本質的區別。首先,C++中的實現文件中什么都沒有,這是因為你并沒有在類中聲明任何的方法。同理,就像Objective-C,一個空類不需要@implemenation/@end模塊。

    在Objective-C中,幾乎每個類都繼承自NSObject。你可以創建自己的根類,這意味著你的類將沒有任何superclass。但是,你可能從來沒有這么做過,除非你只是為了運行時好玩兒。對比C++,正如上面的例子一樣,創建一個沒有超類的類是很普遍的。

    另外一個微小的區別是#include和#import。Objective-C將#import預處理器指令添加到C。在C++中沒有相同的,標準的C-style是使用#include。Objective-C中的#import是確保一個文件只被包含一次,但在C++中你必須自己檢查。

    類成員變量和成員函數

    當然,有比聲明一個類多得多的事情。正如,在Objective-C和C++中,你可以在類中添加實例變量和方法。或許,你知道在C++中這兩個不是這樣命名的,C++中通常稱為成員變量和成員函數。

     注意:“method(實體方法)”這個術語通常不用于C++中,這個特性只用在Objective-C中。在Objective-C中,通過消息分派帶調用“method(實體方法)”。另外,function(函數)通過一個靜態的C-style函數被調用。稍后在這篇文章中我將更多的解釋靜態和動態。

    那么接下來你要如何聲明成員變量和成員函數呢?如下:

    1
    2
    3
    4
    5
    6
    7
    8
    class MyClass {
        int x;
        int y;
        float z;
        void foo();
        void bar();
    };

    這里有三個成員變量和兩個成員函數。但是在C++中這里要有更多,在C++中,你可以限定成員變量和成員函數的范圍,并且可以聲明它們是公開訪問的還是私有訪問的。這個可以用于限制什么代碼可以訪問每個變量或者函數。

    思考下面這個例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MyClass {
      public:
        int x;
        int y;
        void foo();
      private:
        float z;
        void bar();
    }

    這里,x,y和foo函數是公開訪問。意思是可以在MyClass類的外部被調用。然而,z和bar函數是私有的。意味著只能在MyClass內部調用被調用。成員變量默認是私有的。

    雖然這種區別確實存在于Objective-C中的實例變量中,但是很少使用。另外,在Objective-C中不太可能限制方法的調用范圍。即使你只是在實現類內部聲明一個方法而沒有在接口中顯示,技術上你還是可以外部調用這個方法。

    Objective-C中的方法只約定為公開或私有。這就是為什么很多開發者選擇給私有方法加前綴(例如“p_”前綴)來定義這個區別。這是為了和C++作比較,在C++中如果你試圖從類的外部調用一個私有方法,編譯器會拋出一個錯誤。

    那么你要怎么使用類呢?和Objective-C非常相似,真的!你可以像下面這樣創建一個實例:

    1
    2
    3
    4
    MyClass m;
    m.x = 10;
    m.y = 20;
    m.foo();

    簡單吧!這里創建了一個MyClass的實例,分別設x=10,y=20,然后調用foo函數。

    實現類的成員函數

    你已經看到了如何定義一個類接口,但是函數呢?事實證明,這個十分簡單。有如下兩種方法你可以定義。

    第一個實現函數的方法是在類的實現文件中定義–.cpp文件。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // MyClass.h
    class MyClass {
        int x;
        int y;
        void foo();
    };
    // MyClass.cpp
    #include “MyClass.h”
    MyClass::foo() {
       // Do something
    }

    以上是第一個方法。在Objective-C中定義十分簡單。注意MyClass::的用法,這就是你如何表明foo()函數已經作為MyClass類的一部分被實現了。

    第二個實現函數的方法是你在Objective-C中不能做到的。在C++中,你可以直接在頭文件中定義一個函數,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    // MyClass.h
    class MyClass {
        int x;
        int y;
        void foo() {
            // Do something
        }
    };

    如果你只用過Objective-C,這看上去會很奇怪。確實奇怪,但是這種方法會十分有用。當一個函數以這種方式被聲明時,編譯器可以執行“內聯”優化。這意味著當函數被調用時,整個函數代碼在調用站點被內聯編譯而不是跳到一個新的代碼塊。

    雖然內聯可以使代碼更快,但會增加編輯器代碼的大小,因為如果函數被多次調用,代碼將通過二進制復制。如果函數很大,或者被調用很多次,那么這可能會對二進制文件的大小產生重大的影響。由于很少的代碼會在緩存中,這將會導致性能下降,這就意味著可能會有潛在的更多的緩存丟失。

    我的目標是舉例證明C++允許更多的靈活性。作為一個開發者,你需要去理解權衡并做決定。當然,唯一能真正明白哪種選擇對你是正確的方法就是測試你的代碼!

    rgergrgerghh092435_1

    命名空間

    上面的例子介紹了一些你之前沒有遇到過的新的語法–雙冒號::,即指在C++中如何指代范圍。雙冒號用來告訴編譯器應該在哪里可以找到foo函數。

    下一次你會在使用命名空間的時候遇到雙冒號。命名空間是分離代碼的一種方式,以便減少命名沖突。

    例如,你可能會在代碼中定義一個叫Person的類,但是一個第三方庫也可能命名一個叫Person的類。因此,在寫C++代碼時,你通常會將你的代碼放到一個命名空間中來避免這些類型的命名沖突。

    很容易做這個,套用以下命名空間聲明即可:

    1
    2
    3
    4
    5
    6
    7
    namespace MyNamespace {
        class Person { … };
    }
    namespace LibraryNamespace {
        class Person { … };
    }

    現在,當使用任何一個Person類的實現時,你可以使用兩個冒號消除歧義,如下:

    1
    2
    MyNamespace::Person pOne;
    LibraryNamespace::Person pTwo;

    簡單吧?

    除了在類前加一個前綴來約定,在Objective-C中沒有類似的命名空間。你確實這樣命名類,對吧?如果不是這樣命名的話,那就馬上這樣做吧!

     注意:在Objective-C中已經有很多命名空間的建議了。這樣的方案可以在這里(鏈接)找到。我不知道在Objective-C中是否還能用到它們,但是我希望如此。

    內存管理

    哦,不……不是那個可怕的詞吧!在任何語言中,內存管理都是需要理解的最重要的概念之一。Java基本上是用內存回收器來管理內存。Objective-C需要你明白引用計數以及ARC所扮演的角色。在C++中,嗯。。。C++又不同了。

    首先,在C++中,要理解內存管理,你需要先了解堆和棧。即使你認為你知道這一點,我建議你繼續往下閱讀,或許你能略有收獲。

    是指用于運行應用程序的一個內存塊。棧大小固定,并用于存儲應用程序的代碼的數據。?;趐uch/pop工作,當一個給定函數將數據壓入棧中,當函數運行結束時,出棧的必須是等量的數據。因此,隨著時間的推移,棧使用率不會增長。

    同樣也是運行應用程序的一個內存塊。堆大小不固定,并且隨著程序的運行而增長。應用程序傾向于使用堆來儲存在函數范圍外使用的數據。此外,大的數據單元通常會存儲到堆中,因為存到棧中有可能會溢出。–記住,棧的大小是固定的。

    以上是一個堆和棧原理的簡述,以下為兩者的C語言示例:

    1
    2
    3
    4
    int stackInt = 5;
    int *heapInt = malloc(sizeof(int));
    *heapInt = 5;
    free(heapInt);

    這里,stackInt使用??臻g。程序返回后,用來存儲“5”的這塊內存就會自動釋放。

    然而,heapInt使用堆空間,在堆上調用malloc分配足夠的空間來存儲一個整數(int)。但是由于堆必須是由你分配,在用完數據后,開發者需要調用一個free函數來確保你沒有內存泄露。

    在Objective-C中,你只能在堆上創建對象。如果你試著在棧上創建對象,那么編譯器就會報錯。根本行不通。

    思考下面的例子:

    1
    2
    3
    4
    5
    6
    NSString stackString;
    // Untitled 32.m:5:18: error: interface type cannot be statically allocated
    //         NSString stackString;
    //                  ^
    //                  *
    // 1 error generated.

    這就是為什么在Objective-C代碼上會看到星號,所有的對象都在堆上創建,并且所有對象都有指針。這在很大程度上歸結為Objective-C處理內存管理。引用計數廣泛應用于Objective-C中,對象需要在堆中以便它們的生命周期能被嚴格控制。

    在C++中你既可以把數據存到棧中也可存到堆中。由開發者自己決定。然而,在C++中你也必須自己管理內存。數據放入棧中時內存將自動被處理;但用堆時,你必須自己管理內存,否則要面臨內存泄露的風險。

    C++中new和delete運算符

    C++中引入一組關鍵詞以幫助堆對象進行內存管理;他們分別用來創建和撤銷堆中的對象。

    創建對象:

    1
    Person *person = new Person();

    當你不用這個對象時,你就要撤銷它:

    1
    delete person;

    事實上,這同樣適用于C++中標量類型:

    1
    2
    3
    int *x = new int();
    *x = 5;
    delete x;

    你可以認為這些運算相當于Objective-C中的初始化和刪除對象。在C++中初始化用的new Person()等同于Objective-C中的[[Person alloc] init]。

    但是,在Objective-C中沒有等同于delete的運算符。但是我想你已經意識到了,當引用計數歸零時,運行時Objective-C對象的存儲單元就會被釋放。記住,C++不會自動處理引用計數,開發者調用對象完成后負責釋放對象。

    現在你對C++的內存管理有了大致了解,簡言之,在C++中的內存管理要比Objective-C中的要復雜得多。你真的需要考慮下一步是怎樣,并且要跟蹤對象。
    fherherheh415092751_1

    訪問棧和堆對象成員

    你已經了解到,C++中既可以在棧上也可以在堆上創建對象。然而,這兩種方法還有一點微妙但是很重要的區別,即訪問成員變量和成員函數的方式稍有不同。

    使用棧對象時,你需要點運算符(.);使用堆對象時,你需要使用箭頭操作符(–>)。如下:

    1
    2
    3
    4
    5
    6
    7
    Person stackPerson;
    stackPerson.name = “Bob Smith”; ///< Setting a member variable
    stackPerson.doSomething(); ///< Calling a member function
    Person *heapPerson = new Person();
    heapPerson->name = “Bob Smith”; ///< Setting a member variable
    heapPerson->doSomething(); ///< Calling a member function

    區別很微妙,但是值得注意。

    你還看到箭頭操作符與this指針一起用,就像在Objective-C中的self指針一樣,它用于類內部函數去訪問當前的對象。

    下面的C++例子展示了箭頭操作符的用法:

    1
    2
    3
    Person::doSomething() {
        this->doSomethingElse();
    }

    這會引起一個常見的C++陷阱。在Objective-C中,你可以用空指針調用一個方法,你的應用程序仍會運行的很好:

    1
    2
    myPerson = nil;
    [myPerson doSomething]; // does nothing

    然而,在C++中,如果你要用一個NULL指針調用一個方法或者訪問一個實例,你的應用程序會崩潰:

    1
    2
    myPerson = NULL;
    myPerson->doSomething(); // crash!

    因此,你必須確保在C++中不要試圖使用空指針。

    引用

    向函數傳遞對象時,你傳遞的是一個對象副本,而不是對象本身。例如,思考下面的C++代碼:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void changeValue(int x) {
        x = 5;
    }
    // …
    int x = 1;
    changeValue(x);
    // x still equals 1

    很簡單,沒什么特別的。但是想一想當用一個函數做同樣的事情,并且這個函數可以把一個對象作為一個參數。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Foo {
      public:
        int x;
    };
    void changeValue(Foo foo) {
        foo.x = 5;
    }
    // …
    Foo foo;
    foo.x = 1;
    changeValue(foo);
    // foo.x still equals 1

    這或許令你有些驚訝。仔細想想的話,和簡單的int型例子沒有不同。在將對象傳遞給函數之前,創建一個Foo object副本會發生什么情況?不過有時候確實需要傳遞一個實際對象。一種方法是改變函數指向對象的指針,而不是對象本身。但是無論什么時候調用函數都會產生附加代碼。

    對比上面列舉的值傳遞的例子, C++定義了一個新的概念來允許通過引用來傳遞變量。這就意味著不需要創建對象副本。

    利用引用傳遞可以很簡單的改變你的調用,你可以在函數簽名前簡單地在變量前使用ampersand (&)即可,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void changeValue(Foo &foo) {
        foo.x = 5;
    }
    // …
    Foo foo;
    foo.x = 1;
    changeValue(foo);
    // foo.x equals 5

    它也適用于non-class變量:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void changeValue(int &x) {
        x = 5;
    }
    // …
    int x = 1;
    changeValue(x);
    // x equals 5

    引用傳遞很有用,并能顯著提高性能。當創建一個對象副本成本相當高的時候引用傳遞更加有用,例如使用一個大型鏈表,創建副本意味著要對對象執行深度復制。
    
    繼承

    一個面向對象的語言沒有繼承就不完整。C++當然不會違反這一趨勢。思考下面的兩個Objective-C類,其中一個類從另一個類繼承:

    1
    2
    3
    4
    5
    @interface Person : NSObject
    @end
    @interface Employee : Person
    @end

    同樣的事情可以用C++以很相似的方式表達:

    1
    2
    3
    4
    5
    class Person {
    };
    class Employee : public Person {
    };

    唯一的區別是在C++中要加一個public關鍵詞。這里Employee類公共的繼承Person類。這就意味著person類中的公共成員在Employee類中也是公共類型的。如果用private代替public,那么Person類中的公共成員在Employee類中就將變為私有的。關于這個話題的更多信息,我建議讀一篇很棒的關于繼承和存儲說明符的文章。

    以上是關于“繼承“的簡單部分,下面我們開始復雜的部分。與Objective-C不同的是,C++中允許多重繼承,即一個類可以繼承兩個或以上基類。如果你除了Objective-C沒有用過其他語言,那么這對你來說一定很陌生。

    下面是C++中多重繼承的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Player {
        void play();
    };
    class Manager {
        void manage();
    };
    class PlayerManager : public Player, public Manager {
    };

    在這個例子中,有兩個基類,一個類繼承這兩個基類。意思是PlayerManager類可以訪問每個基類的所有成員變量和函數。簡單吧?我確定你已經意識到了,在Objective-C中沒有這種方法。

    然而,這并不完全正確,對吧?

    精明的讀者一定注意到在Objective-C中有類似的方法,即protocols(協議)。雖然跟多重繼承不太相似,但是兩種技術都為了解決同樣的問題:提供一個機制來連接兩個有相似用途的類。

    Protocols(協議)有一個微小的區別,那就是協議沒有實現,只是描述類必須遵循哪個接口。

    在Objective-C中,上面的例子可被寫成:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @protocol Player
    - (void)play;
    @end
    @protocol Manager
    - (void)manage;
    @end
    @interface Player : NSObject <Player>
    @end
    @interface Manager : NSObject <Manager>
    @end
    @interface PlayerManager : NSObject <Player, Manager>
    @end

    當然,這個細小的差別你是能想象的到的。在Objective-C中你要在PlayerManager類中執行play和manager。在C++中你只要在每個基類中實現該方法,然后PlayerManager類會自動的繼承每個實現。

    雖然,在實踐中,多重繼承有時會另人混淆和復雜化。對C++開發者來說,多重繼承是一個危險的方法,除非絕對必要,開發者會盡量避免使用。

    為什么呢?想一想如果兩個基類用同樣的名字去實現一個函數,并接受同樣的參數的話,那么這兩個基類就會有同樣的原型。在這種情況下,你就需要消除歧義。例如,假設Player和Manager兩個類都有一個命名為foo的函數。

    你需要這樣消除歧義:

    1
    2
    3
    4
    PlayerManager p;
    p.foo();          ///< Error! Which foo?
    p.Player::foo();  ///< Call foo from Player
    p.Manager::foo(); ///< Call foo from Manager

    這絕對是可行的,但是這增加了混淆,而且最好避免復雜性。這由PlayerManager類的使用者決定。使用協議直接使PlayerManager類實現函數foo,因此這里只有一次實現,沒有混淆。

    下一步

    第一部分中我們了解了C++的簡史,如何聲明類以及C++中內存管理是如何工作的。當然,關于C++還有很多需要學習的!

    第二部分中,在查閱Objective-C和C++標準庫之前,學到了更多的高級類的特征和模板。

    與此同時,如果你在學C++的過程中有任何問題或者觀點,請加入下面的討論!

    2 收藏 1 評論

      本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
      轉藏 分享 獻花(0

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 国产欧美日韩精品丝袜高跟鞋| 天天拍夜夜添久久精品大| 无码国模国产在线观看免费| 亚洲一区二区三区无码中文字幕| 色猫咪av在线网址| 99视频30精品视频在线观看| 午夜久久久久久禁播电影| 人妻中文字幕亚洲一区| 丰满少妇人妻HD高清大乳在线| 国产在线观看播放av| 少妇富婆高级按摩出水高潮| 99久久亚洲综合精品成人网| 美女内射无套日韩免费播放| 精品久久人人做爽综合| 免费人妻无码不卡中文字幕18禁 | 天天做日日做天天添天天欢公交车| 爽爽影院免费观看| 久久这里只精品国产免费9| 亚洲制服丝袜系列AV无码| 奇米777四色成人影视| 各种少妇wbb撒尿| 国产高跟黑色丝袜在线| 亚洲国产精品日韩在线| 内射毛片内射国产夫妻| 国产免费午夜福利757| 亚洲国产精品无码一区二区三区 | 五月天国产成人AV免费观看| 亚洲另类激情专区小说图片| 激情97综合亚洲色婷婷五| 国产午夜福利精品视频| 夜夜未满十八勿进的爽爽影院| 成年福利片在线观看| 韩国无码AV片午夜福利| 成人H动漫精品一区二区无码| 欧美综合婷婷欧美综合五月 | 亚洲色大成网站WWW永久麻豆| 久久精品国产99久久久古代| 老色鬼久久亚洲AV综合| 久热综合在线亚洲精品| 亚洲精品国产中文字幕| 人人妻人人狠人人爽|