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

對象和類
Swfit C++
關鍵字 class class / struct

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

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

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

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

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

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

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

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

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

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

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

struct NamedShape {
    
    NamedShape() = default;
    NamedShape(const string name): name(name) { // 冒號后是構造函數(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)建類的時候并不需要一個標準的根類; 而子類如果要重寫父類的方法的話, 需要用override 標記 —— 如果沒有添加override 就重寫父類方法的話, 編譯器會報錯, 同樣編譯器也能檢測到你用override 標記的方法是否確實在父類中:

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()

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

C++中子類的定義方法和 Swift 中子類定義方法相同, 不過, 在初始化父類的數(shù)據(jù)成員時, 必須調(diào)用父類的構造函數(shù)來初始化.子類重寫父類的成員函數(shù)可以在成員函數(shù)后面顯式添加override 關鍵字, 不過, 子類中要重寫的成員函數(shù),父類中必須使用virtual標記; 注意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;
}

練習:創(chuàng)建 NamedShape 的另一個子類 Circle ,構造器接收兩個參數(shù),一個是半徑一個是名稱,在子類 Circle 中實現(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 之后顯式的設置一個名字。注意 EquilateralTriangle 類的構造器執(zhí)行了三步:

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

如果你不需要計算屬性,但是仍然需要在設置一個新值之前或者之后運行代碼,使用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, ? 后面的東西都會被忽略,并且整個表達式返回 nil 。否則, ? 之后的東西都會被運行。在這兩種情況下,整個表達式的值都是一個可選值:

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


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

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

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

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