【Swift 3 && C++11】<第一部分> 概覽(4): Swift對象和類 與 C++對象和類

對象和類
Swfit C++
關(guān)鍵字 class class / struct

Swift 中使用class 后加類名來創(chuàng)建一個類. 類中的屬性聲明, 方法和函數(shù)聲明與普通的常量,變量,函數(shù)的聲明一樣:

class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

練習(xí): 使用 let 添加一個常量屬性,再添加一個接收一個參數(shù)的方法。

而要創(chuàng)建一個類的實(shí)例, 在類名后面加上括號. 使用點(diǎn)語法來訪問實(shí)例的屬性和方法:

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

C++中使用 classstruct 后加類名來創(chuàng)建一個類, 它們的唯一區(qū)別就是默認(rèn)訪問權(quán)限不太一樣. 類中的數(shù)據(jù)成員,成員函數(shù)與普通的變量,函數(shù)聲明一樣,只是不能使用 auto 來定義非常量非靜態(tài)的類成員; 而要創(chuàng)建一個類的實(shí)例, 在類名后面加上括號或者與普通聲明變量一樣, 使用類名. 使用點(diǎn)語法來訪問實(shí)例的屬性和方法:

#include <iostream>
#include <string>
using namespace std;

struct Shape {
    
    static const auto constAutoNumber = 0;
    int numberOfSides = 0;
    
    auto simpleDescription() -> string {
        return "A shape with " + to_string(numberOfSides) + "sides.";
    }
};


int main() {
    
    auto shape = Shape();
    Shape shape2;
    
    shape.numberOfSides = 7;
    auto shapeDescription = shape.simpleDescription();
    
    return 0;
}

練習(xí): 在類中添加一個常量數(shù)據(jù)成員, 再添加一個成員函數(shù),它接受一個參數(shù).

Swift 中使用 init 來創(chuàng)建一個構(gòu)造器來初始化實(shí)例, 注意self 被用來區(qū)別實(shí)例變量.當(dāng)創(chuàng)建實(shí)例的時候, 先傳入函數(shù)參數(shù)一樣給類傳入構(gòu)造器的參數(shù). 每個屬性都需要賦值—— 不管是通過聲明(就像numberOfSides)還是通過構(gòu)造器(就像name); 而使用deinit 創(chuàng)建一個析構(gòu)函數(shù)值刪除對象之前進(jìn)行一些清理工作:

class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    deinit {
        // do some cleanup before the object is deallocated.
    }
    
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

C++中如果沒有定義任何的構(gòu)造函數(shù),編譯器會自動創(chuàng)建它; 對于大多數(shù)類來說, 對數(shù)據(jù)成員的初始化,如果存在類內(nèi)初始值,用它來初始化成員(就像 numberOfSides),否則,默認(rèn)初始化該成員. 構(gòu)造函數(shù)名和類名相同, 不寫返回類型, 默認(rèn)構(gòu)造函數(shù)沒有參數(shù),可以使用= default 來使用默認(rèn)行為; 有參數(shù)的構(gòu)造函數(shù)可以使用構(gòu)造函數(shù)初始值列表; 構(gòu)造函數(shù)初始值列表是在構(gòu)造函數(shù)參數(shù)列表后面的初始化列表; 銷毀對象之前,可以在析構(gòu)函數(shù)中進(jìn)行一些必須的操作, 析構(gòu)函數(shù)是一個波浪號接類名構(gòu)成,它沒有返回值,也不接受參數(shù); 一個類只有唯一一個析構(gòu)函數(shù):

#include <iostream>
#include <string>
using namespace std;

struct NamedShape {
    
    NamedShape() = default;
    NamedShape(const string name): name(name) { // 冒號后是構(gòu)造函數(shù)初始值列表
        
    }
    ~NamedShape() {

    }
    
    static const auto constAutoNumber = 0;
    int numberOfSides = 0;
    string name;
    
    auto simpleDescription() -> string {
        return "A shape with " + to_string(numberOfSides) + "sides.";
    }
};


int main() {
    
    auto shape = Shape();
    Shape shape2("shape2");
    auto shape3 = Shape("shape3");
    
    
    shape.numberOfSides = 7;
    auto shapeDescription = shape.simpleDescription();
    
    return 0;
}

Swift 中子類定義的方法是在他們的類名后面加上父類的名字,用冒號分割.創(chuàng)建類的時候并不需要一個標(biāo)準(zhǔn)的根類; 而子類如果要重寫父類的方法的話, 需要用override 標(biāo)記 —— 如果沒有添加override 就重寫父類方法的話, 編譯器會報(bào)錯, 同樣編譯器也能檢測到你用override 標(biāo)記的方法是否確實(shí)在父類中:

class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() ->  Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

練習(xí): 創(chuàng)建 NamedShape 的另一個子類 Circle ,構(gòu)造器接收兩個參數(shù),一個是半徑一個是名稱,在子類 Circle 中實(shí)現(xiàn) area()simpleDescription() 方法。

C++中子類的定義方法和 Swift 中子類定義方法相同, 不過, 在初始化父類的數(shù)據(jù)成員時, 必須調(diào)用父類的構(gòu)造函數(shù)來初始化.子類重寫父類的成員函數(shù)可以在成員函數(shù)后面顯式添加override 關(guān)鍵字, 不過, 子類中要重寫的成員函數(shù),父類中必須使用virtual標(biāo)記; 注意this 的使用, 它是指向本對象自身的指針:

#include <iostream>
#include <string>
using namespace std;

struct NamedShape {
    
    NamedShape() = default;
    NamedShape(const string name): name(name) {
        
    }
    ~NamedShape() {

    }
    
    static const auto constAutoNumber = 0;
    int numberOfSides = 0;
    string name;

    virtual auto simpleDescription() -> string {
        return "A shape with " + to_string(numberOfSides) + "sides.";
    }
};

struct Square: NamedShape {
    
    double sideLength;
    Square(double sideLength, string name) : sideLength(sideLength), NamedShape(name) {
        this->numberOfSides = 4;
    }
    
    auto area() -> double {
        return sideLength * sideLength;
    }
    
    auto simpleDescription()  -> string override {
        
        return "A square with sides of length " + to_string(sideLength) + ".";
    }
};


int main() {
    
    auto test = Square(5.2, "my test square");
    
    test.area();
    test.simpleDescription();
    
    return 0;
}

練習(xí):創(chuàng)建 NamedShape 的另一個子類 Circle ,構(gòu)造器接收兩個參數(shù),一個是半徑一個是名稱,在子類 Circle 中實(shí)現(xiàn) area()simpleDescription() 方法。

Swift 中除了存儲屬性之外, 屬性還可以有 getter 和 setter:

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get {
             return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }

    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)

perimeter 的 setter 中,新值的名字是 newValue 。你可以在 set 之后顯式的設(shè)置一個名字。注意 EquilateralTriangle 類的構(gòu)造器執(zhí)行了三步:

  1. 設(shè)置子類聲明的屬性值
  2. 調(diào)用父類的構(gòu)造器
  3. 改變父類定義的屬性值。其他的工作比如調(diào)用方法、getters和setters也可以在這個階段完成。

如果你不需要計(jì)算屬性,但是仍然需要在設(shè)置一個新值之前或者之后運(yùn)行代碼,使用willSetdidSet 。比如,下面的類確保三角形的邊長總是和正方形的邊長相同:

class TriangleAndSquare {
    var triangle: EquilateralTriangle {
        willSet {
            square.sideLength = newValue.sideLength
        }
    }
    var square: Square {
        willSet {
            triangle.sideLength = newValue.sideLength
        }
    }
    init(size: Double, name: String) {
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)

處理變量的可選值時,你可以在操作(比如方法、屬性和子腳本)之前加 ? 。如果 ? 之前的值是 nil, ? 后面的東西都會被忽略,并且整個表達(dá)式返回 nil 。否則, ? 之后的東西都會被運(yùn)行。在這兩種情況下,整個表達(dá)式的值都是一個可選值:

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength


Swift 的屬性有存儲屬性和計(jì)算屬性兩種, 存儲屬性相當(dāng)于 C++中的數(shù)據(jù)成員, 而計(jì)算屬性相當(dāng)于C++中寫的成員函數(shù). Swift 中的方法或函數(shù), 也相當(dāng)于** C++**中的成員函數(shù).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容