Swift 中的继承和可见性

问题描述 投票:0回答:1

我对 swift 文档中的内容感到困惑:

请注意,等边三角形类的初始化程序具有三个不同的步骤:

  1. 设置子类声明的属性值。
  2. 调用超类的初始化器。
  3. 更改超类定义的属性值。任何使用方法、getter 或 setter 的附加设置工作也可以在此时完成。

然后我在 Swift 和 C++ 中尝试下面的示例:

斯威夫特
class Base {
    init() {
        print("Enter Base");
        setUp();
        print("Leave Base");
    }
    func setUp() -> Void {
        print("base setUp()")
    }
}

class Derived: Base {  
    let number: Int;
    override init () {      
        number = 5;
    }
    override func setUp() -> Void {
        print("derived setUp() \(number)")
    }
}

let d = Derived()
let b = Base()
Enter Base
derived setUp() 5
Leave Base
Enter Base
base setUp()
Leave Base
C++
#include <iostream>
#include <string>

class Base {
public:
    Base() {
        std::cout << "Enter Base" << std::endl;
        setUp();
        std::cout << "Leave Base" << std::endl;
    }
    virtual void setUp() {
        std::cout << "base setUp()" << std::endl;
    }
};

class Derived: public Base {  
    int number;
public:
    Derived () {
        number = 5;
    }
    void setUp() override {
        std::cout << "derived setUp() " << number << std::endl;
    }
};

int main()
{
  Derived d = Derived();
  Base b = Base();
}
Enter Base
base setUp()
Leave Base
Enter Base
base setUp()
Leave Base

根据上面的两个输出,很明显 C++ 和 Swift 在继承理念方面存在差异。有人可以解释为什么两种语言之间的行为不同(为什么 Swift 允许超类访问子类方法)?

我已经了解了C++中的vtable及其机制,但我对Swift一无所知,所以如果你能比较一下两种语言之间底层实现的差异就好了。

c++ swift inheritance vtable
1个回答
0
投票

在 C++ 中,基类在派生类之前完全初始化。调用超类构造函数是派生类构造函数首先要做的事情之一。这意味着,如果您要在基类构造函数中调用派生类的

setUp
setUp
将观察到未初始化的
number
。这是不可取的,因为编写
setUp
的人可能会假设所有字段都已初始化(尽管在调用该方法时不太可能发生这种情况
setUp
)。因此,构造函数中的虚拟方法调用被设计为静态分派。另请参阅这篇文章了解更多详细信息。

另一方面,Swift 以相反的顺序初始化类。首先初始化派生类。

super.init
只能在初始化派生类中声明的所有存储属性后才能调用。 class Derived: Base { let number: Int override init() { super.init() // this is not allowed! number = 5 } }

因此,在基类初始化器中调用虚方法是安全的。当它被调用时,所有派生类存储的属性都保证被初始化。

© www.soinside.com 2019 - 2024. All rights reserved.