美文网首页iOS Developer程序员
【Swift 3 && C++11】<第一

【Swift 3 && C++11】<第一

作者: 大刀和长剑 | 来源:发表于2016-10-24 16:35 被阅读39次
    对象和类
    Swfit C++
    关键字 class class / struct

    Swift 中使用class 后加类名来创建一个类. 类中的属性声明, 方法和函数声明与普通的常量,变量,函数的声明一样:

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

    练习: 使用 let 添加一个常量属性,再添加一个接收一个参数的方法。

    而要创建一个类的实例, 在类名后面加上括号. 使用点语法来访问实例的属性和方法:

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

    C++中使用 classstruct 后加类名来创建一个类, 它们的唯一区别就是默认访问权限不太一样. 类中的数据成员,成员函数与普通的变量,函数声明一样,只是不能使用 auto 来定义非常量非静态的类成员; 而要创建一个类的实例, 在类名后面加上括号或者与普通声明变量一样, 使用类名. 使用点语法来访问实例的属性和方法:

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

    练习: 在类中添加一个常量数据成员, 再添加一个成员函数,它接受一个参数.

    Swift 中使用 init 来创建一个构造器来初始化实例, 注意self 被用来区别实例变量.当创建实例的时候, 先传入函数参数一样给类传入构造器的参数. 每个属性都需要赋值—— 不管是通过声明(就像numberOfSides)还是通过构造器(就像name); 而使用deinit 创建一个析构函数值删除对象之前进行一些清理工作:

    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++中如果没有定义任何的构造函数,编译器会自动创建它; 对于大多数类来说, 对数据成员的初始化,如果存在类内初始值,用它来初始化成员(就像 numberOfSides),否则,默认初始化该成员. 构造函数名和类名相同, 不写返回类型, 默认构造函数没有参数,可以使用= default 来使用默认行为; 有参数的构造函数可以使用构造函数初始值列表; 构造函数初始值列表是在构造函数参数列表后面的初始化列表; 销毁对象之前,可以在析构函数中进行一些必须的操作, 析构函数是一个波浪号接类名构成,它没有返回值,也不接受参数; 一个类只有唯一一个析构函数:

    #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;
        
        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 中子类定义的方法是在他们的类名后面加上父类的名字,用冒号分割.创建类的时候并不需要一个标准的根类; 而子类如果要重写父类的方法的话, 需要用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()
    

    练习: 创建 NamedShape 的另一个子类 Circle ,构造器接收两个参数,一个是半径一个是名称,在子类 Circle 中实现 area()simpleDescription() 方法。

    C++中子类的定义方法和 Swift 中子类定义方法相同, 不过, 在初始化父类的数据成员时, 必须调用父类的构造函数来初始化.子类重写父类的成员函数可以在成员函数后面显式添加override 关键字, 不过, 子类中要重写的成员函数,父类中必须使用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;
    }
    

    练习:创建 NamedShape 的另一个子类 Circle ,构造器接收两个参数,一个是半径一个是名称,在子类 Circle 中实现 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 类的构造器执行了三步:

    1. 设置子类声明的属性值
    2. 调用父类的构造器
    3. 改变父类定义的属性值。其他的工作比如调用方法、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++中的数据成员, 而计算属性相当于C++中写的成员函数. Swift 中的方法或函数, 也相当于** C++**中的成员函数.

    相关文章

      网友评论

        本文标题:【Swift 3 && C++11】<第一

        本文链接:https://www.haomeiwen.com/subject/rudluttx.html