在Swift中初始化子类时调用父构造函数

时间:2016-02-16 17:09:02

标签: swift

我有一些继承自基类的类。通常使用c ++类,我习惯在子代中重写构造函数,然后调用父类。

在初始化子类而不重写子类时,Swift中是否有一种方法可以调用父构造函数?

internal class A {
    init(aBool: Bool? = false) {
        ...
    }
}

class B: A {
    init(aString: String) {
        ...
    }
}

以这两个类为例,我想使用A构造函数初始化B:

let obj = A(true)

2 个答案:

答案 0 :(得分:12)

The rules from Apple声明:

  

[S] ubclasses默认不继承其超类初始值设定项。但是,如果满足某些条件,则会自动继承超类初始值设定项。实际上,这意味着您不需要在许多常见场景中编写初始化程序覆盖,并且可以在安全的情况下以最小的努力继承您的超类初始化程序。

     

假设您为在子类中引入的任何新属性提供默认值,则适用以下两个规则:

     

规则1:   如果您的子类没有定义任何指定的初始值设定项,它会自动继承其所有超类指定的初始值设定项。

     

规则2:   如果您的子类提供了所有超类指定初始化器的实现 - 通过按照规则1继承它们,或者通过提供自定义实现作为其定义的一部分 - 那么它会自动继承所有超类便捷初始化器。

     

即使您的子类添加了更多便利初始值设定项,这些规则也适用。

这意味着什么?如果您将子类B的初始值设定项设置为便捷初始值设定项,则B应继承所有A指定的初始值设定项。

class B: A {
    convenience init(aString: String) { ... }
}

答案 1 :(得分:5)

如果您#include <iostream> #include <cstring> extern "C" { #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netdb.h> #include <arpa/inet.h> #include <netinet/in.h> } int main(int argc, char *argv[]) { if(argc != 3) { std::cerr << "Run program as 'program ipaddress port'" << std::endl; return -1; } auto &ipAddress = argv[1]; auto &portNum = argv[2]; struct addrinfo hints, *res, *p; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; int gAddRes = getaddrinfo(ipAddress, portNum, &hints, &res); if(gAddRes != 0) { std::cerr << gai_strerror(gAddRes) << std::endl; return -2; } std::cout << "Detecting addresses" << std::endl; unsigned int numOfAddr = 0; char ipStr[INET6_ADDRSTRLEN]; for(p = res; p != NULL; p = p->ai_next) { void *addr; std::string ipVer = "IPv0"; if(p->ai_family == AF_INET) { ipVer = "IPv4"; struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; addr = &(ipv4->sin_addr); ++numOfAddr; } else { ipVer = "IPv6"; struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); ++numOfAddr; } inet_ntop(p->ai_family, addr, ipStr, sizeof(ipStr)); std::cout << "(" << numOfAddr << ") " << ipVer << " : " << ipStr << std::endl; } if(!numOfAddr) { std::cerr << "Found no host address to use" << std::endl; return -3; } std::cout << "Enter the number of host address to bind with:" << std::endl; unsigned int choice = 0; bool madeChoice = false; do { std::cin >> choice; if(choice > (numOfAddr + 1) || choice < 1) { madeChoice = false; std::cout << "Wrong choice, try again!" << std::endl; } else madeChoice = true; } while(!madeChoice); p = res; bool isIPv4 = true; if(choice > 1) { unsigned int temp = 1; while(choice < temp) { p = p->ai_next; ++temp; } if(p->ai_family == AF_INET) { isIPv4 = true; } else isIPv4 = false; } int sockFD = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if(sockFD == -1) { std::cerr << "Error while creating socket" << std::endl; return -4; } int connectR = connect(sockFD, p->ai_addr, p->ai_addrlen); if(connectR == -1) { close(sockFD); std::cerr << "Error while connecting socket" << std::endl; return -5; } std::string message; message.reserve(5); auto len = message.capacity(); auto bytes_recv = recv(sockFD, &message.front(), len - 1, 0); message[len] = 0; close(sockFD); freeaddrinfo(res); std::cout << "Bytes recieved :" << bytes_recv << std::endl; std::cout << message.c_str() << std::endl; return 0; } 初始化B,则不会屏蔽原始convenience init,您就可以执行此操作...

init

您必须小心默认或以其他方式设置所有属性,但是......

或者,您可以class A { var b: Bool? = nil init(aBool: Bool? = false) { self.b = aBool } } class B: A { var s: String? = nil convenience init(aString: String) { self.init(aBool: false) self.s = aString } } let obj1 = A(aBool: true) // obj1 is now an A, obviously. let obj2 = B(aBool: true) // obj2 is now a B override中的原始init,然后只需致电B