Tại sao lại dùng struct thay vì class c
Tôi đang tham gia một lớp học về Lập trình hướng đối tượng trong C ++. Trong một nhiệm vụ gần đây, tôi đã xác định một chức năng thành viên trong a struct. Người hướng dẫn của tôi giải thích rằng, mặc dù có thể biên dịch để sử dụng các hàm thành viên trong các cấu trúc, nhưng ông ấy muốn chúng tôi không làm như vậy, vì khả năng tương thích ngược với C và (đặc biệt là trong lớp dành cho người mới bắt đầu này) để thực hành đóng gói dữ liệu tốt - chúng ta nên sử dụng a structcho các loại chứa chủ yếu là dữ liệu và classdành cho các ứng dụng được hưởng lợi từ việc đóng gói theo thủ tục nhiều hơn. Anh ấy chỉ ra rằng thực tiễn này xuất phát từ lịch sử của các cấu trúc / lớp trong C ++, đó là điều tôi muốn biết thêm. Tôi biết rằng cấu trúc có chức năng giống như các lớp ngoại trừ quyền truy cập thành viên / kế thừa mặc định. Câu hỏi của tôi là: Tại sao các lớp cấu trúc AND được bao gồm trong C ++? Từ nền tảng của tôi về C #, nơi cấu trúc và lớp có những khác biệt quan trọng, có vẻ như structtrong C ++ chỉ là một đường cú pháp để xác định các lớp với public-ness mặc định. Là nó? Tôi không tìm kiếm ý kiến về việc khi nào / tại sao nên sử dụng một cái này thay vì cái kia- Tôi sinh ra tốt sau những cấu trúc này, và tôi đang tìm kiếm lịch sử của chúng. Họ đã được thụ thai cùng nhau? Nếu vậy, tại sao? Nếu không, cái nào đến trước và tại sao cái thứ hai được thêm vào? Tôi nhận thấy rằng có rất nhiều người lớn tuổi đáng kính trong cộng đồng này, những người có thể còn nhớ về nguồn gốc của các tính năng này và các liên kết đến các ấn phẩm tiêu chuẩn, hoặc ví dụ về mã, nơi cả hai, một hoặc khác xuất hiện lần đầu tiên, sẽ bổ sung thêm cho sự hữu ích của câu trả lời . Xin lưu ý, câu hỏi này không phải là : 6/15/2014 6:33:02 PMTrần Lộc An · Trần Lộc An 18:33 15/06/2014 Chơi xung quanh với Swift, đến từ nền Java, tại sao bạn muốn chọn Struct thay vì Class? Có vẻ như chúng giống nhau, với Struct cung cấp ít chức năng hơn. Tại sao chọn nó sau đó?
432 hữu ích 5 bình luận 133k xem chia sẻ answer Phan Diễm Phương · Phan Diễm Phương 18:37 15/06/2014 Theo Chương trình định hướng giao thức nói chuyện WWDC 2015 rất phổ biến trong Swift ( video , bảng điểm ), Swift cung cấp một số tính năng giúp cấu trúc tốt hơn các lớp trong nhiều trường hợp. Cấu trúc được ưu tiên hơn nếu chúng tương đối nhỏ và có thể ghép được vì sao chép an toàn hơn nhiều so với việc có nhiều tham chiếu đến cùng một thể hiện như xảy ra với các lớp. Điều này đặc biệt quan trọng khi chuyển xung quanh một biến sang nhiều lớp và / hoặc trong môi trường đa luồng. Nếu bạn luôn có thể gửi một bản sao của biến của bạn đến những nơi khác, bạn không bao giờ phải lo lắng về nơi khác thay đổi giá trị của biến bên dưới bạn. Với Structs, sẽ không cần phải lo lắng nhiều về việc rò rỉ bộ nhớ hoặc nhiều luồng chạy đua để truy cập / sửa đổi một thể hiện của một biến. . Các lớp cũng có thể trở nên cồng kềnh vì một lớp chỉ có thể kế thừa từ một siêu lớp duy nhất. Điều đó khuyến khích chúng ta tạo ra những chiếc siêu xe khổng lồ bao gồm nhiều khả năng khác nhau chỉ liên quan một cách lỏng lẻo. Sử dụng các giao thức, đặc biệt là với các phần mở rộng giao thức nơi bạn có thể cung cấp các triển khai cho các giao thức, cho phép bạn loại bỏ sự cần thiết của các lớp để đạt được loại hành vi này. Bài nói chuyện đưa ra các kịch bản trong đó các lớp được ưu tiên:
Nó ngụ ý rằng các cấu trúc nên là mặc định và các lớp nên là một dự phòng. Mặt khác, tài liệu Ngôn ngữ lập trình Swift có phần mâu thuẫn:
Ở đây có tuyên bố rằng chúng ta nên mặc định sử dụng các lớp và chỉ sử dụng các cấu trúc trong các trường hợp cụ thể. Cuối cùng, bạn cần hiểu hàm ý của các loại giá trị trong thế giới thực so với các loại tham chiếu và sau đó bạn có thể đưa ra quyết định có căn cứ về thời điểm sử dụng cấu trúc hoặc các lớp. Ngoài ra, hãy nhớ rằng các khái niệm này luôn phát triển và Tài liệu Ngôn ngữ lập trình Swift đã được viết trước khi bài nói chuyện Lập trình hướng giao thức được đưa ra. 505 hữu ích 5 bình luận chia sẻ answer Trịnh Chính Thuận · Trịnh Chính Thuận 12:22 16/06/2014 Vì các thể hiện cấu trúc được phân bổ trên ngăn xếp và các thể hiện lớp được phân bổ trên heap, các cấu trúc đôi khi có thể nhanh hơn rất nhiều. Tuy nhiên, bạn nên luôn tự đo nó và quyết định dựa trên trường hợp sử dụng duy nhất của bạn. Xem xét ví dụ sau, thể hiện 2 chiến lược gói Intkiểu dữ liệu bằng cách sử dụng structvà class. Tôi đang sử dụng 10 giá trị lặp lại là để phản ánh tốt hơn thế giới thực, nơi bạn có nhiều trường. class Int10Class { let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int init(_ val: Int) { self.value1 = val self.value2 = val self.value3 = val self.value4 = val self.value5 = val self.value6 = val self.value7 = val self.value8 = val self.value9 = val self.value10 = val } } struct Int10Struct { let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int init(_ val: Int) { self.value1 = val self.value2 = val self.value3 = val self.value4 = val self.value5 = val self.value6 = val self.value7 = val self.value8 = val self.value9 = val self.value10 = val } } func + (x: Int10Class, y: Int10Class) -> Int10Class { return IntClass(x.value + y.value) } func + (x: Int10Struct, y: Int10Struct) -> Int10Struct { return IntStruct(x.value + y.value) }Hiệu suất được đo bằng cách sử dụng // Measure Int10Class measure("class (10 fields)") { var x = Int10Class(0) for _ in 1...10000000 { x = x + Int10Class(1) } } // Measure Int10Struct measure("struct (10 fields)") { var y = Int10Struct(0) for _ in 1...10000000 { y = y + Int10Struct(1) } } func measure(name: String, @noescape block: () -> ()) { let t0 = CACurrentMediaTime() block() let dt = CACurrentMediaTime() - t0 print("\(name) -> \(dt)") }Mã có thể được tìm thấy tại https://github.com/knguyen2708/SturationVsClassPerformance CẬP NHẬT (27 tháng 3 năm 2018) : Kể từ Swift 4.0, Xcode 9.2, đang chạy Bản dựng phát hành trên iPhone 6S, iOS 11.2.6, cài đặt Trình biên dịch Swift là -O -whole-module-optimization:
(Tôi không còn trung bình nhiều lần chạy, vì phương sai rất nhỏ, dưới 5%) Lưu ý : sự khác biệt là rất ít kịch tính mà không cần tối ưu hóa toàn bộ mô-đun. Tôi rất vui nếu ai đó có thể chỉ ra những gì cờ thực sự làm. CẬP NHẬT (ngày 7 tháng 5 năm 2016) : Kể từ Swift 2.2.1, Xcode 7.3, chạy Bản dựng phát hành trên iPhone 6S, iOS 9.3.1, trung bình trên 5 lần chạy, cài đặt Trình biên dịch Swift là -O -whole-module-optimization:
Lưu ý : như ai đó đã đề cập rằng trong các kịch bản trong thế giới thực, có thể có nhiều hơn 1 trường trong một cấu trúc, tôi đã thêm các thử nghiệm cho các cấu trúc / lớp với 10 trường thay vì 1. Đáng ngạc nhiên, kết quả không thay đổi nhiều. KẾT QUẢ NGUỒN GỐC (ngày 1 tháng 6 năm 2014): (Chạy trên struct / class với 1 trường chứ không phải 10) Kể từ Swift 1.2, Xcode 6.3.2, chạy Bản dựng phát hành trên iPhone 5S, iOS 8.3, trung bình trên 5 lần chạy
KẾT QUẢ OLD (từ thời gian không xác định) (Chạy trên struct / class với 1 trường chứ không phải 10) Với bản phát hành trên MacBook Pro của tôi:
150 hữu ích 5 bình luận chia sẻ answer Ngô Thu Ngọc · Ngô Thu Ngọc 00:03 04/03/2015 Tôi đã tạo ra ý chính cho điều này với các ví dụ đơn giản. https://github.com/objc-swift/swift-groupes-vs- cấu trúc Và sự khác biệtcấu trúc không thể kế thừa trong nhanh chóng. Nếu bạn muốn class Vehicle{ } class Car : Vehicle{ }Đi cho một lớp học. 2. Đi quaCác cấu trúc Swift truyền theo giá trị và các thể hiện lớp chuyển qua tham chiếu. Sự khác biệt về bối cảnhCấu trúc hằng và biến Ví dụ (Được sử dụng tại WWDC 2014) struct Point{ var x = 0.0; var y = 0.0; }Xác định một cấu trúc gọi là Điểm. var point = Point(x:0.0,y:2.0)Bây giờ nếu tôi cố gắng thay đổi x. Đó là một biểu thức hợp lệ. point.x = 5Nhưng nếu tôi xác định một điểm là hằng số. let point = Point(x:0.0,y:2.0) point.x = 5 //This will give compile time error.Trong trường hợp này toàn bộ điểm là hằng số bất biến. Nếu tôi đã sử dụng một Điểm lớp thay vì đây là một biểu thức hợp lệ. Bởi vì trong một hằng số bất biến lớp là tham chiếu đến chính lớp đó không phải là các biến thể hiện của nó (Trừ khi các biến đó được định nghĩa là hằng số) 59 hữu ích 3 bình luận chia sẻ answer Hồ Sỹ Phú · Hồ Sỹ Phú 22:09 16/01/2015 Dưới đây là một số lý do khác để xem xét:
Để có được điều này trong một lớp, bạn sẽ phải thêm trình khởi tạo và duy trì intializer ...
28 hữu ích 5 bình luận chia sẻ answer Phạm Trúc Vy · Phạm Trúc Vy 02:12 25/06/2016 Giả sử rằng chúng ta biết Struct là một loại giá trị và Class là một loại tham chiếu . Nếu bạn không biết loại giá trị và loại tham chiếu là gì thì hãy xem Sự khác biệt giữa chuyển qua tham chiếu so với chuyển qua giá trị là gì? Dựa trên bài đăng của mikeash :
Ngoài ra, không sử dụng lớp khi bạn phải ghi đè từng và mọi phiên bản của hàm, tức là chúng không có bất kỳ chức năng chia sẻ nào . Vì vậy, thay vì có một vài lớp con của một lớp. Sử dụng một số cấu trúc phù hợp với một giao thức. 19 hữu ích 1 bình luận chia sẻ answer Nguyễn Thành Đức · Nguyễn Thành Đức 18:38 15/06/2014 Một số ưu điểm:
18 hữu ích 5 bình luận chia sẻ answer Nguyễn Vân Linh · Nguyễn Vân Linh 12:25 10/05/2016 Cấu trúc nhanh hơn nhiều so với Class. Ngoài ra, nếu bạn cần kế thừa thì bạn phải sử dụng Class. Điểm quan trọng nhất là Class là loại tham chiếu trong khi Cấu trúc là loại giá trị. ví dụ, class Flight { var id:Int? var description:String? var destination:String? var airlines:String? init(){ id = 100 description = "first ever flight of Virgin Airlines" destination = "london" airlines = "Virgin Airlines" } } struct Flight2 { var id:Int var description:String var destination:String var airlines:String }bây giờ cho phép tạo cá thể của cả hai. var flightA = Flight() var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )bây giờ cho phép chuyển các thể hiện này đến hai hàm sửa đổi id, mô tả, đích, v.v. func modifyFlight(flight:Flight) -> Void { flight.id = 200 flight.description = "second flight of Virgin Airlines" flight.destination = "new york" flight.airlines = "Virgin Airlines" }cũng thế, func modifyFlight2(flight2: Flight2) -> Void { var passedFlight = flight2 passedFlight.id = 200 passedFlight.description = "second flight from virgin airlines" }vì thế, Bây giờ nếu chúng tôi in id và mô tả của chuyến bay, chúng tôi sẽ nhận được id = 200 description = "second flight of Virgin Airlines"Ở đây, chúng ta có thể thấy id và mô tả của FlightA bị thay đổi do tham số được truyền cho phương thức sửa đổi thực sự trỏ đến địa chỉ bộ nhớ của đối tượng FlightA (kiểu tham chiếu). bây giờ nếu chúng ta in id và mô tả về cá thể FLightB chúng ta nhận được, id = 100 description = "first ever flight of Virgin Airlines"Ở đây chúng ta có thể thấy rằng thể hiện của FlightB không bị thay đổi bởi vì trong phương thức redirectFlight2, thể hiện thực tế của Flight2 được truyền thay vì tham chiếu (kiểu giá trị). 12 hữu ích 4 bình luận chia sẻ answer Dương Tuấn Hải · Dương Tuấn Hải 13:19 05/09/2016 Trả lời câu hỏi từ góc độ của các loại giá trị so với các loại tham chiếu, từ bài đăng trên blog này của Apple, nó sẽ xuất hiện rất đơn giản:
Như đã đề cập trong bài viết đó, một lớp không có thuộc tính có thể ghi sẽ hoạt động giống hệt với cấu trúc, với (tôi sẽ thêm) một cảnh báo: cấu trúc là tốt nhất cho các mô hình an toàn luồng - một yêu cầu ngày càng sắp xảy ra trong kiến trúc ứng dụng hiện đại. 4 hữu ích 0 bình luận chia sẻ answer Lý Kiết Trinh · Lý Kiết Trinh 18:36 15/06/2014 Với các lớp bạn có được sự kế thừa và được truyền bằng tham chiếu, các cấu trúc không có sự kế thừa và được truyền theo giá trị. Có những phiên WWDC tuyệt vời trên Swift, câu hỏi cụ thể này được trả lời rất chi tiết trong một trong số đó. Hãy chắc chắn rằng bạn xem những thứ đó, vì nó sẽ giúp bạn tăng tốc nhanh hơn nhiều so với hướng dẫn Ngôn ngữ hoặc iBook. 3 hữu ích 3 bình luận chia sẻ answer Huỳnh Bảo Quốc · Huỳnh Bảo Quốc 09:06 15/06/2016 Tôi sẽ không nói rằng structs cung cấp ít chức năng hơn. Chắc chắn, bản thân là bất biến ngoại trừ trong một chức năng đột biến, nhưng đó là về nó. Kế thừa hoạt động tốt miễn là bạn tuân theo ý tưởng cũ tốt rằng mọi lớp nên là trừu tượng hoặc cuối cùng. Thực hiện các lớp trừu tượng như các giao thức và các lớp cuối cùng như các cấu trúc. Điều thú vị về cấu trúc là bạn có thể làm cho các trường của mình có thể thay đổi mà không cần tạo trạng thái có thể thay đổi được chia sẻ vì sao chép trên ghi chú quan tâm đến điều đó :) Đó là lý do tại sao các thuộc tính / lĩnh vực trong ví dụ sau đều có thể thay đổi, mà tôi sẽ không làm trong Java hoặc C # hoặc nhanh chóng lớp . Cấu trúc kế thừa ví dụ với một chút sử dụng bẩn và đơn giản ở phía dưới trong hàm có tên "ví dụ": protocol EventVisitor { func visit(event: TimeEvent) func visit(event: StatusEvent) } protocol Event { var ts: Int64 { get set } func accept(visitor: EventVisitor) } struct TimeEvent : Event { var ts: Int64 var time: Int64 func accept(visitor: EventVisitor) { visitor.visit(self) } } protocol StatusEventVisitor { func visit(event: StatusLostStatusEvent) func visit(event: StatusChangedStatusEvent) } protocol StatusEvent : Event { var deviceId: Int64 { get set } func accept(visitor: StatusEventVisitor) } struct StatusLostStatusEvent : StatusEvent { var ts: Int64 var deviceId: Int64 var reason: String func accept(visitor: EventVisitor) { visitor.visit(self) } func accept(visitor: StatusEventVisitor) { visitor.visit(self) } } struct StatusChangedStatusEvent : StatusEvent { var ts: Int64 var deviceId: Int64 var newStatus: UInt32 var oldStatus: UInt32 func accept(visitor: EventVisitor) { visitor.visit(self) } func accept(visitor: StatusEventVisitor) { visitor.visit(self) } } func readEvent(fd: Int) -> Event { return TimeEvent(ts: 123, time: 56789) } func example() { class Visitor : EventVisitor { var status: UInt32 = 3; func visit(event: TimeEvent) { print("A time event: \(event)") } func visit(event: StatusEvent) { print("A status event: \(event)") if let change = event as? StatusChangedStatusEvent { status = change.newStatus } } } let visitor = Visitor() readEvent(1).accept(visitor) print("status: \(visitor.status)") }2 hữu ích 0 bình luận chia sẻ answer Trịnh Ngọc Nhung · Trịnh Ngọc Nhung 09:45 22/10/2017
Mô hình sáng tạo: Trong swift, Struct là một loại giá trị được tự động nhân bản. Do đó, chúng tôi nhận được các hành vi cần thiết để thực hiện mẫu nguyên mẫu miễn phí. Trong khi đó các lớp là kiểu tham chiếu, không được tự động nhân bản trong quá trình gán. Để thực hiện mẫu nguyên mẫu, các lớp phải áp dụng NSCopyinggiao thức. Bản sao nông chỉ sao chép tham chiếu, trỏ đến các đối tượng đó trong khi sao chép sâu sao chép tham chiếu của đối tượng. Thực hiện sao chép sâu cho từng loại tham chiếu đã trở thành một nhiệm vụ tẻ nhạt. Nếu các lớp bao gồm loại tham chiếu xa hơn, chúng ta phải triển khai mẫu nguyên mẫu cho từng thuộc tính tham chiếu. Và sau đó chúng ta phải thực sự sao chép toàn bộ biểu đồ đối tượng bằng cách thực hiện NSCopyinggiao thức. class Contact{ var firstName:String var lastName:String var workAddress:Address // Reference type } class Address{ var street:String ... }Bằng cách sử dụng structs và enums , chúng tôi đã làm cho mã của chúng tôi đơn giản hơn vì chúng tôi không phải thực hiện logic sao chép. 2 hữu ích 0 bình luận chia sẻ answer Phạm Thục Nghi · Phạm Thục Nghi 11:17 17/11/2016 Nhiều API ca cao yêu cầu các lớp con NSObject, điều này buộc bạn phải sử dụng lớp. Nhưng ngoài ra, bạn có thể sử dụng các trường hợp sau từ blog Swift của Apple để quyết định nên sử dụng loại giá trị struct / enum hay loại tham chiếu lớp. https://developer.apple.com/swift/blog/?id=10 1 hữu ích 0 bình luận chia sẻ answer Lê Mai Anh · Lê Mai Anh 21:14 03/12/2018 Structsđang value typevà Classesđangreference type
Sử dụng một valueloại khi:
Sử dụng một referenceloại khi:
Thông tin thêm cũng có thể được tìm thấy trong tài liệu của Apple https://docs.swift.org/swift-book/L LanguageGuide / C gốmAndSt Structures.html thông tin thêm Các loại giá trị Swift được giữ trong ngăn xếp. Trong một quy trình, mỗi luồng có không gian ngăn xếp riêng, do đó, không có luồng nào khác có thể truy cập trực tiếp vào loại giá trị của bạn. Do đó không có điều kiện chủng tộc, khóa, khóa chết hoặc bất kỳ sự phức tạp đồng bộ hóa chủ đề liên quan. Các loại giá trị không cần phân bổ bộ nhớ động hoặc đếm tham chiếu, cả hai đều là các hoạt động đắt tiền. Đồng thời phương thức trên các loại giá trị được gửi tĩnh. Những điều này tạo ra một lợi thế rất lớn trong việc ủng hộ các loại giá trị về hiệu suất. Xin nhắc lại ở đây là danh sách Swift Các loại giá trị:
Các loại tham khảo:
1 hữu ích 0 bình luận chia sẻ answer Trịnh Ðài Trang · Trịnh Ðài Trang 12:57 19/12/2017 Một điểm không nhận được sự chú ý trong các câu trả lời này là một biến giữ một lớp so với cấu trúc có thể lettrong một thời gian vẫn cho phép thay đổi các thuộc tính của đối tượng, trong khi bạn không thể làm điều này với một cấu trúc. Điều này hữu ích nếu bạn không muốn biến bao giờ trỏ đến một đối tượng khác, nhưng vẫn cần sửa đổi đối tượng, tức là trong trường hợp có nhiều biến đối tượng mà bạn muốn cập nhật lần lượt từng đối tượng. Nếu nó là một cấu trúc, bạn phải cho phép biến lại thành một đối tượng khác hoàn toàn bằng cách sử dụng varđể thực hiện điều này, vì một loại giá trị không đổi trong Swift đúng cho phép không có đột biến, trong khi các loại tham chiếu (các lớp) không hành xử theo cách này. 0 hữu ích 0 bình luận chia sẻ answer Phạm Hạnh Vi · Phạm Hạnh Vi 12:35 23/05/2018 Vì struct là các loại giá trị và bạn có thể tạo bộ nhớ rất dễ dàng lưu trữ vào stack. Cấu trúc có thể dễ dàng truy cập và sau phạm vi công việc, nó dễ dàng được giải phóng khỏi bộ nhớ ngăn xếp thông qua pop từ đầu ngăn xếp. Mặt khác, lớp là kiểu tham chiếu lưu trữ trong đống và các thay đổi được thực hiện trong một đối tượng lớp sẽ tác động đến đối tượng khác vì chúng được liên kết chặt chẽ và kiểu tham chiếu. Tất cả các thành viên của cấu trúc đều công khai trong khi tất cả các thành viên của lớp là riêng tư . Nhược điểm của struct là nó không thể được kế thừa. 0 hữu ích 0 bình luận chia sẻ answer Võ Thy Trúc · Võ Thy Trúc 11:31 13/08/2018
7 hữu ích 2 bình luận chia sẻ Xem nguồn: https://stackoverflow.com//questions/24232799/why-choose-struct-over-class |