lớp trong ngôn ngữ OOP và loại


9

Trong lý thuyết ngôn ngữ lập trình, một loại là một tập hợp các giá trị. Ví dụ, kiểu "int" là tập hợp của tất cả các giá trị nguyên.

Trong các ngôn ngữ OOP, một lớp là một loại, phải không?

Khi một lớp được định nghĩa có nhiều thành viên, vd

class myclass{
    int a; 
    double b;
}

Khi chúng ta nói về một lớp học, chúng ta có nghĩa là

  • " (a,b)trong đó alà một int và blà một đôi", hoặc
  • "{ (x,y)| xlà bất kỳ int, ylà bất kỳ gấp đôi}"?

Một ví dụ myclasscó nghĩa là gì?

  • " (a,b)trong đó alà một int và blà một đôi", hoặc
  • một đối tượng chiếm một không gian bộ nhớ và có thể (không nhất thiết, có thể trống) (x,y), nơi xnào có int và ycó bất kỳ gấp đôi không?

2
Một lớp là một loại. "{(X, y) | x là bất kỳ int nào, y là bất kỳ double}" " sẽ gần như đúng, ngoại trừ hai điều: 1) bạn đã sử dụng một tuple trong khi một lớp về mặt khái niệm là một bản ghi - bạn đề cập đến nó các trường theo tên, không phải vị trí và 2) Không phải mọi bản ghi đều có các trường ablà thành viên của loại đó, như Killian Forth đề cập. Lớp học của tôi là đẳng cấu với các bản ghi với các trường abloại intdouble- bạn có thể lấy một bản ghi như thế và biến nó thành một ví dụ của myclass.
Doval

1
Trong các ngôn ngữ được gõ mạnh, một lớp là một loại. Trong các ngôn ngữ gõ yếu, nó có thể hoặc không phải là một loại.
Shawnhcorey

1
Trong lý thuyết ngôn ngữ lập trình, một loại là một tập hợp các giá trị? Tôi nghĩ bạn cần có cho mình một cuốn sách khác hoặc giáo viên khác hoặc cả hai. Một "biến" hoặc "hằng số" có "loại" và thường có "giá trị". Có các loại giá trị 0, vô hướng và các loại giá trị tổng hợp trong đó giá trị của biến hoặc hằng chứa các biến phụ / hằng phụ.
dùng1703394

1
@ user1703394 Một loại một tập hợp các giá trị. Loại số nguyên 32 bit là một tập hợp gồm 2 ^ 32 giá trị riêng biệt. Nếu một biểu thức ước lượng cho một giá trị của loại đó, bạn biết rằng giá trị đó nằm trong tập đó. Các toán tử toán học chỉ là các hàm trên các giá trị của tập hợp đó.
Doval

1
Tôi cũng sẽ thận trọng khi xem các loại là tập hợp các giá trị. Các bộ có quan hệ không được áp dụng đúng cho các loại. Đối với các kiểu khái niệm hóa, đó là một mô hình tốt, nhưng nó bị hỏng khi bạn bắt đầu xem xét mọi thứ kỹ hơn - và thậm chí ngay cả khi bạn giới thiệu phân nhóm.
Telastyn

Câu trả lời:


30

Cũng không.

Tôi hỏi bạn đang hỏi liệu có cùng một loại trường trường có đủ để phân loại là cùng một lớp hay không hoặc chúng có phải được đặt tên giống hệt không. Câu trả lời là: "Thậm chí không có cùng loại cùng tên là đủ!" Các lớp tương đương về cấu trúc không nhất thiết phải tương thích kiểu.

Ví dụ: nếu bạn có một CartesianCoordinatesvà một PolarCordinateslớp, cả hai có thể có hai số là các trường của chúng và thậm chí chúng có thể có cùng Numberloại và cùng tên, nhưng chúng vẫn không tương thích và một trường hợp PolarCoordinatessẽ không phải là một thể hiện của CartesianCoordinates. Khả năng phân tách các loại theo mục đích dự định của chúng và không phải là triển khai hiện tại của chúng là một phần rất hữu ích để viết mã an toàn hơn, dễ bảo trì hơn.


9
Cần lưu ý rằng trong một số ngôn ngữ có cấu trúc tương đương đủ để biến một loại thành một kiểu con của loại kia (và thường ngược lại). Điều đó mặc dù được quyết định là không phổ biến / không phổ biến.
Telastyn

7
@Tim Một typedef không tạo ra một loại, nó đặt bí danh cho tên được sử dụng để chỉ một loại hiện có.
Doval

1
@DevSolar Ông đã đề cập rõ ràng đến C, và ngoài C ++, tôi không biết bất kỳ ngôn ngữ nào khác sử dụng từ khóa đó.
Doval

3
@Telastyn - những ngôn ngữ đó nên bị giết bằng lửa.
Câu chuyện Jon

4
@JonStory Subtyping cấu trúc là hữu ích ở cấp độ mô-đun; thiếu nó là điều buộc bạn phải biến mọi thứ thành interfaceJava và C # nếu bạn muốn thử nghiệm đơn vị. Cuối cùng, bạn chỉ viết một tấn nồi hơi để bạn có thể thay đổi lớp cụ thể mà chương trình của bạn sẽ sử dụng mặc dù bạn không có ý định thay đổi nó khi chạy.
Doval

6

Các loại không phải là bộ.

Bạn thấy, lý thuyết tập hợp có một số tính năng đơn giản là không áp dụng cho các loại và ngược lại . Chẳng hạn, một đối tượng có một kiểu chính tắc duy nhất. Nó có thể là một thể hiện của một số loại khác nhau, nhưng chỉ một trong những loại đó được sử dụng để khởi tạo nó. Lý thuyết tập hợp không có khái niệm về tập hợp "chính tắc".

Lý thuyết tập hợp cho phép bạn tạo các tập hợp con một cách nhanh chóng , nếu bạn có một quy tắc mô tả những gì thuộc về tập hợp con. Lý thuyết loại thường không cho phép điều này. Mặc dù hầu hết các ngôn ngữ có một Numberloại hoặc một cái gì đó tương tự, chúng không có một EvenNumberloại, cũng không đơn giản để tạo ra một loại. Ý tôi là, nó đủ dễ để tự xác định loại, nhưng bất kỳ Numbers nào hiện có thậm chí sẽ không được chuyển đổi một cách kỳ diệu thành EvenNumbers.

Trên thực tế, việc nói rằng bạn có thể "tạo ra" các tập hợp con có phần không rõ ràng, bởi vì bộ là một loại động vật hoàn toàn khác. Trong lý thuyết tập hợp, những tập hợp con đó đã tồn tại , theo tất cả các cách vô hạn mà bạn có thể định nghĩa chúng. Trong lý thuyết loại, chúng ta thường mong đợi được xử lý một số loại hữu hạn (nếu lớn) tại bất kỳ thời điểm nào. Các loại duy nhất được cho là tồn tại là những loại chúng tôi thực sự đã xác định, không phải mọi loại chúng tôi có thể xác định.

Các bộ không được phép chứa trực tiếp hoặc gián tiếp . Một số ngôn ngữ, chẳng hạn như Python, cung cấp các loại có cấu trúc ít thông thường hơn (trong Python, typeloại chính tắc là typeobjectđược coi là một thể hiện của object). Mặt khác, hầu hết các ngôn ngữ không cho phép các loại do người dùng xác định tham gia vào loại mánh khóe này.

Các bộ thường được phép chồng lên nhau mà không được chứa trong nhau. Điều này không phổ biến trong lý thuyết loại, mặc dù một số ngôn ngữ hỗ trợ nó dưới dạng đa thừa kế. Các ngôn ngữ khác, chẳng hạn như Java, chỉ cho phép một hình thức hạn chế này hoặc không cho phép hoàn toàn.

Loại trống tồn tại (nó được gọi là loại dưới cùng ), nhưng hầu hết các ngôn ngữ không hỗ trợ nó, hoặc không coi nó là loại hạng nhất. "Loại chứa tất cả các loại khác" cũng tồn tại (nó được gọi là loại hàng đầu ) và được hỗ trợ rộng rãi, không giống như lý thuyết tập hợp.

Lưu ý : Như một số nhà bình luận trước đây đã chỉ ra (trước khi chủ đề được chuyển sang trò chuyện), có thể mô hình hóa các loại với lý thuyết tập hợp và các cấu trúc toán học tiêu chuẩn khác. Chẳng hạn, bạn có thể mô hình thành viên kiểu như một mối quan hệ thay vì mô hình hóa thành các tập hợp. Nhưng trong thực tế, điều này đơn giản hơn nhiều nếu bạn sử dụng lý thuyết thể loại thay vì lý thuyết tập hợp. Đây là cách Haskell mô hình lý thuyết loại của nó, ví dụ.


Khái niệm "phân nhóm" thực sự khá khác biệt với khái niệm "tập hợp con". Nếu Xlà một kiểu con của Ynó, điều đó có nghĩa là chúng ta có thể thay thế các thể hiện của Ycác trường hợp Xvà chương trình vẫn sẽ "hoạt động" theo một nghĩa nào đó. Đây là hành vi chứ không phải cấu trúc, mặc dù một số ngôn ngữ (ví dụ: Go, Rust, được cho là C) đã chọn ngôn ngữ sau vì lý do thuận tiện, cho người lập trình hoặc thực hiện ngôn ngữ.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Kỹ sư thế giới

4

Các loại dữ liệu đại số là cách để thảo luận về điều này.

Có ba cách cơ bản bạn có thể kết hợp các loại:

  • Sản phẩm. Về cơ bản đó là những gì bạn nghĩ về:

    struct IntXDouble{
      int a; 
      double b;
    }
    

    là một loại sản phẩm; giá trị của nó là tất cả các kết hợp có thể (ví dụ: bộ dữ liệu) của một intvà một double. Nếu bạn coi các loại số là tập hợp, thì tính chính xác của loại sản phẩm trên thực tế là sản phẩm của các yếu tố chính của các trường.

  • Tổng. Trong các ngôn ngữ thủ tục, điều này hơi khó để diễn đạt trực tiếp (theo cách cổ điển, nó được thực hiện với các hiệp hội được gắn thẻ ), vì vậy để hiểu rõ hơn, đây là một loại tổng trong Haskell:

    data IntOrDouble = AnInt Int
                     | ADouble Double
    

    các giá trị của loại này có dạng AnInt 345, hoặc ADouble 4.23, nhưng luôn chỉ có một số liên quan (không giống với loại sản phẩm, trong đó mỗi giá trị có hai số). Vì vậy, cardinality: trước tiên bạn liệt kê tất cả các Intgiá trị, mỗi giá trị phải được kết hợp với hàm AnInttạo. Cộng , tất cả các Doublegiá trị, mỗi giá trị kết hợp với ADouble. Do đó tổng loại .

  • Lũy thừa 1 . Tôi sẽ không thảo luận chi tiết về vấn đề này ở đây vì nó không có sự tương ứng rõ ràng nào cả.

Vậy còn lớp học thì sao? Tôi cố tình sử dụng từ khóa structchứ không phải classcho IntXDouble. Vấn đề là, một lớp dưới dạng không thực sự được đặc trưng bởi các trường của nó, chúng chỉ là các chi tiết triển khai. Yếu tố cốt yếu là, lớp có thể có những giá trị phân biệt nào.

Điều liên quan là, giá trị của một lớp có thể là giá trị của bất kỳ lớp con nào của nó ! Vì vậy, một lớp thực sự là một loại tổng chứ không phải là một loại sản phẩm: nếu ABcả hai đều có nguồn gốc từ myClass, về myClasscơ bản sẽ là tổng của AB. Bất kể thực hiện thực tế.


1 Đây là hàm (theo nghĩa toán học! ); một loại hàm Int -> Doubleđược biểu diễn theo cấp số nhân DoubleInt. Thật tệ nếu ngôn ngữ của bạn không có chức năng phù hợp ...


2
Xin lỗi, nhưng tôi nghĩ rằng đây là một câu trả lời rất kém. Chức năng làm có một tương tự OO rõ ràng, cụ thể là phương pháp (và các loại giao diện duy nhất-method). Định nghĩa cơ bản của một đối tượng là nó có cả trạng thái (trường / thành viên dữ liệu) và hành vi (phương thức / hàm thành viên); câu trả lời của bạn bỏ qua cái sau.
ruakh

@ruakh: không. Tất nhiên bạn có thể thực hiện các hàm trong OO, nhưng nói chung, các phương thức không phải là các hàm ( chúng sửa đổi trạng thái, v.v.). Cũng không phải là "chức năng" trong các chức năng ngôn ngữ thủ tục, cho vấn đề đó. Thật vậy, các giao diện phương thức tĩnh đơn gần nhất với các kiểu hàm / hàm mũ, nhưng tôi hy vọng tránh được cuộc thảo luận về điều đó bởi vì nó không liên quan đến câu hỏi này.
rẽ trái

... quan trọng hơn, anwer của tôi không xem xét hành vi. Thực tế hành vi thường là lý do tại sao bạn sử dụng tính kế thừa và việc thống nhất các hành vi có thể khác nhau nắm bắt chính xác khía cạnh kiểu tổng của các lớp OO.
rẽ trái

@ruakh Một phương thức không thể không có đối tượng của nó. Tương tự gần nhất là staticcác phương thức, ngoại trừ chúng vẫn không phải là giá trị hạng nhất. Vấn đề của hầu hết các ngôn ngữ OO là chúng lấy các đối tượng làm khối xây dựng nhỏ nhất, vì vậy nếu bạn muốn bất kỳ thứ gì nhỏ hơn bạn phải giả nó với các đối tượng, và cuối cùng bạn vẫn kéo theo một loạt các hàm ngữ nghĩa không nên có. Ví dụ, không có nghĩa gì khi so sánh các hàm cho đẳng thức, nhưng bạn vẫn có thể so sánh hai đối tượng hàm giả.
Doval

@Doval 1) bạn có thể truyền các phương thức xung quanh AFAIK, vì vậy chúng là các giá trị hạng nhất; 2) thật hợp lý khi so sánh các hàm cho sự bình đẳng, mọi người làm điều đó mọi lúc.
Den

2

Xin lỗi nhưng tôi không biết về lý thuyết "thô". Tôi chỉ có thể cung cấp một cách tiếp cận thực tế. Tôi hy vọng điều này được chấp nhận tại các lập trình viên. E; Tôi không quen thuộc với nghi thức ở đây.


Một chủ đề trung tâm của OOP là ẩn thông tin . Chính xác thì các thành viên dữ liệu của một lớp sẽ không được khách hàng quan tâm. Một khách hàng gửi tin nhắn đến (gọi các phương thức / hàm thành viên của) một thể hiện, có thể hoặc không thể sửa đổi trạng thái bên trong. Ý tưởng là các phần bên trong của một lớp có thể thay đổi, mà không có khách hàng bị ảnh hưởng bởi nó.

Một điều đáng mừng cho điều này là lớp có trách nhiệm đảm bảo rằng đại diện bên trong của nó vẫn "hợp lệ". Giả sử một lớp lưu trữ số điện thoại (đơn giản hóa) theo hai số nguyên:

    int areacode;
    int number;

Đây là những thành viên dữ liệu của lớp. Tuy nhiên, lớp có lẽ sẽ nhiều hơn so với chỉ các thành viên dữ liệu của nó, và nó chắc chắn là không thể xác định được là "tập hợp tất cả các giá trị có thể có của int x int". Bạn không nên truy cập trực tiếp vào các thành viên dữ liệu.

Xây dựng một thể hiện có thể từ chối bất kỳ số âm. Có lẽ việc xây dựng cũng sẽ bình thường hóa mã vùng theo một cách nào đó, hoặc thậm chí xác minh toàn bộ số. Do đó, bạn sẽ kết thúc gần hơn với bạn "(a,b) where a is an int and b is a double", bởi vì đó chắc chắn không phải là bất kỳ hai int nào được lưu trữ trong lớp đó.

Nhưng điều đó không thực sự quan trọng đối với lớp học. Nó không phải là kiểu của các thành viên dữ liệu, cũng không phải là phạm vi của các giá trị có thể có của chúng xác định lớp, đó là các phương thức được định nghĩa cho nó.

Miễn là các phương thức đó vẫn giữ nguyên, người triển khai có thể thay đổi các kiểu dữ liệu thành dấu phẩy động, BIGNUM, chuỗi, bất cứ điều gì và cho tất cả các mục đích thực tế, nó vẫn sẽ là cùng một lớp .


Có các patters thiết kế để đảm bảo rằng những thay đổi của biểu diễn bên trong có thể được thực hiện mà không cần khách hàng biết về nó (ví dụ: thành ngữ pimpl trong C ++, ẩn bất kỳ thành viên dữ liệu nào phía sau một con trỏ mờ ).


1
It is neither the type of the data members, nor the range of their possible values that defines the class, it's the methods that are defined for it.Các thành viên dữ liệu không định nghĩa một lớp chỉ khi bạn ẩn chúng. Đó có thể là trường hợp phổ biến nhất, nhưng chắc chắn không thể nói rằng nó đúng với tất cả các lớp. Nếu ngay cả một lĩnh vực duy nhất được công khai thì nó cũng quan trọng như các phương thức của nó.
Doval

1
Trừ khi bạn đang viết mã bằng Java, trong đó bạn không có sự lựa chọn nào trong vấn đề này và ngay cả các bản ghi giả không có hành vi ngu ngốc của bạn cũng phải là classes. (Đánh dấu chúng finalgiúp có được điểm, nhưng vẫn). Bạn vẫn có một vấn đề với protectedcác thành viên, điều này có thể được kế thừa và do đó tạo thành một phần của API thứ hai cho những người triển khai các lớp con.
Doval

1
@Doval: Tôi hiểu đây là một câu hỏi "lý thuyết", đó là lý do tại sao tôi hiểu rõ các vấn đề ngôn ngữ thực tế nhất có thể. (Giống như tôi hiểu rõ về Java và protectedcàng tốt trong thực tế
.;

3
Vấn đề là a classlà một cấu trúc phụ thuộc ngôn ngữ. Theo như tôi biết thì không có thứ gọi là classlý thuyết loại.
Doval

1
@Doval: Sẽ không có nghĩa là loại lý thuyết cho mỗi gia nhập không áp dụng cho các lớp học, vì họ là một cấu trúc ra khỏi phạm vi của lý thuyết đó?
DevSolar

2
  • Một loại là một mô tả về một loại / phạm vi của các giá trị, cấu trúc ghép hoặc những gì có bạn. OOPwise, nó giống như một "giao diện". (Trong ý nghĩa ngôn ngữ-agnostic. Ý nghĩa ngôn ngữ cụ thể, không quá nhiều. Trong Java, ví dụ, intlà một loại , nhưng không có liên quan đến một interface. Cộng / thông số kỹ thuật lĩnh vực bảo vệ, cũng như, không phải là một phần của một interface, nhưng một phần của "giao diện" hoặc loại .)

    Điểm chính là, đó là một định nghĩa ngữ nghĩa nhiều hơn là một định nghĩa cụ thể. Cấu trúc chỉ các yếu tố trong inasmuch như các lĩnh vực / hành vi tiếp xúc và mục đích xác định của chúng phù hợp với nhau. Nếu bạn không có cả hai, bạn không có khả năng tương thích.

  • Một lớp là sự hiện thực hóa của một loại. Đó là một mẫu thực sự xác định cấu trúc bên trong, hành vi đính kèm, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.