STL có được thực hiện với OO không?


8

Có một số mẫu thiết kế như Adaptor, Iterator được triển khai trong STL.

Điều đó có nghĩa là STL được thực hiện với các khái niệm OO?
Mối quan hệ giữa OO và các phần mẫu của C ++ là gì?

Tôi đã học được rằng hàm thành viên ảo điều chỉnh OO trái ngược với khuôn mẫu, điều này có đúng không?


4
Nhà thiết kế của STL nổi tiếng chống OO. vi.wikipedia.org/wiki/Alexander_Stepanov#Criticism_of_OOP
ném đá

Câu trả lời:


11

Đầu tiên, "STL" không phải là một thuật ngữ chính thức, nó là tên của thư viện được đề xuất để đưa vào Thư viện chuẩn C ++ khi không có thùng chứa. Nó cung cấp về cơ bản các mẫu container và thuật toán.

Bây giờ, các mẫu container và thuật toán này là ... các mẫu để chúng tạo ra các loại khi cần thiết. Họ không dựa vào sự kế thừa từ quan điểm của người dùng.

Tuy nhiên, thư viện tiêu chuẩn chỉ định về cơ bản giao diện của thư viện, không phải việc thực hiện. Rất nhiều triển khai STL sẽ sử dụng một chút định hướng đối tượng khi triển khai nhưng với tư cách là người dùng, bạn sẽ không thấy nó nếu bạn không đi sâu vào mã nguồn triển khai của mình (phải được trình bày vì về cơ bản là mã mẫu).

Tôi đã học được rằng hàm thành viên ảo điều chỉnh OO trái ngược với khuôn mẫu, điều này có đúng không?

Không, chúng là những khái niệm trực giao cung cấp những lợi thế và nhược điểm rất khác nhau. Trong thực tế trong C ++, một trong những lợi thế chính để sử dụng ngôn ngữ như vậy là bạn có cả khả dụng và sử dụng một ngôn ngữ không hủy bằng ngôn ngữ kia. Nó thậm chí là một lợi thế rất lớn. Ví dụ, một trong những thành ngữ thú vị nhất trong C ++ là CRTP sử dụng cả mẫu và kế thừa. Ý tưởng là phần kế thừa cho phép bạn mở rộng một số loại với một hành vi và dữ liệu chung, như một lớp cơ sở; trong khi phần mẫu đảm bảo tạo các lớp cơ sở cụ thể cho từng đứa trẻ, không thể có một con trỏ tới tất cả các lớp sử dụng lớp CRTP làm cơ sở. Điều này cực kỳ hữu ích và không cho phép gây rối với quyền thừa kế ở những nơi không nên có.

Tôi cũng đã triển khai các hệ thống gửi sự kiện rất chung chung không biết loại sự kiện hoặc loại người nghe nhưng kết hợp mã động và mã tĩnh bên trong cùng nhau cho phép tạo ra các loại nội bộ phù hợp với các loại thời gian chạy phù hợp.

Và đó là điểm chính: bạn không phải lúc nào cũng cần "hướng đối tượng". Trong thực tế, hầu hết thời gian bạn không cần nó, bạn cần xác định một số loại và sử dụng chúng trực tiếp như một phần khác nhau của một loại công cụ trừu tượng (sáng tác). Bạn không phải lúc nào cũng cần mã chung, hay còn gọi là các mẫu. Đôi khi bạn cần nó để khái quát hóa một chức năng để áp dụng cho một số loại không liên quan. Khi chúng có liên quan, bạn có thể sử dụng lớp cơ sở của chúng thay thế và không cần mẫu.

Chúng có những lợi thế khác nhau và chi phí hoàn toàn khác nhau, vì vậy chúng rất tốt để kết hợp để giải quyết các vấn đề phức tạp.

STL là một ví dụ điển hình cho vấn đề trong đó phần lớn là về việc cung cấp các loại (thùng chứa) và các hàm (thuật toán) có liên quan đến một loại nhất định thay vì phân cấp các đối tượng thời gian chạy. Trong thư viện chuẩn, các luồng được tạo theo cách điển hình cho hướng đối tượng: đó là một hệ thống phân cấp của các lớp luồng thực hiện các việc khác nhau theo cách cho phép xác định lớp luồng phụ kết hợp các hành vi / năng lực khác nhau. Ở đó, định hướng đối tượng là hữu ích, ngay cả khi một số người thích nó giống với STL hơn (tôi không phải là chuyên gia về chủ đề này).

Vì vậy, chỉ cần nghĩ về chúng như những công cụ rất khác nhau, như một cái tuốc nơ vít và một cái búa. C ++ đừng để bạn suy nghĩ chỉ với một công cụ.


8

Trên thực tế, STL đã giới thiệu mô hình Lập trình chung cho dòng chính.

Khi tôi được dạy về mô hình lập trình hướng đối tượng (bởi một số giáo sư) 15 năm trước, tôi đã được dạy ba trụ cột quan trọng là đóng gói, kế thừa và đa hình (ngày nay có lẽ phải đủ điều kiện là đa hình thời gian chạy ), trong khi Wikipedia hiện tại liệt kê trừu tượng hóa dữ liệu, đóng gói, nhắn tin, mô đun hóa, đa hình và kế thừa như xác định các đặc tính OOP. Tất nhiên, STL sử dụng một số trong số chúng, như đóng gói, nhưng sau đó nó cũng sử dụng các hàm, một đặc điểm của mô hình Lập trình có cấu trúc . Tuy nhiên, không ai có thể tranh luận rằng STL là lập trình có cấu trúc .

Lưu ý rằng một trong những tính năng mạnh nhất của C ++ là nó hỗ trợ nhiều mô hình lập trình (Cấu trúc, Hướng đối tượng, Chung chung, Lập trình chức năng và các tính năng khác) và nó tỏa sáng nhất khi bạn trộn và trộn chúng.


7

Để trích dẫn Alexander Stepanov từ cuộc phỏng vấn STLPort của mình :

STL không hướng đối tượng. Tôi nghĩ rằng tính định hướng đối tượng gần như là một trò lừa bịp như Trí tuệ nhân tạo. Tôi vẫn chưa thấy một đoạn mã thú vị đến từ những người OO này. [...] Tôi thấy OOP không có căn cứ về mặt triết học. Nó tuyên bố rằng tất cả mọi thứ là một đối tượng. Ngay cả khi đó là sự thật thì nó cũng không thú vị lắm - nói rằng mọi thứ là một đối tượng không nói gì cả. Tôi thấy OOP sai về phương pháp.

Điều đó nói rằng, một triển khai cá nhân có thể được thực hiện bằng cách sử dụng tính kế thừa và đa hình ở những nơi. Ví dụ, tôi đã thấy một triển khai iteratorđược bắt nguồn từ const_iteratorđể hỗ trợ chuyển đổi ngầm định từ iteratorsang const_iterator. Tuy nhiên, phái sinh không phải là đặc trưng của, hoặc được yêu cầu bởi thiết kế.

Điểm mấu chốt: trong khi bạn có thể / có thể sử dụng mã hướng đối tượng để triển khai một số phần của STL, thì thiết kế của chính STL là (chắc chắn) không hướng đối tượng.


3

Không, tôi muốn nói rằng STL không đặc biệt là OO, nếu có bất cứ điều gì nó ánh xạ nhiều hơn đến một phong cách lập trình chức năng. Đặc biệt:

  • thuật toán std :: là các hàm miễn phí không phải là phương thức
  • họ thường lấy các đối tượng hàm như vậy :. là các hàm bậc cao hơn
  • họ hoạt động trên bất kỳ container
  • std :: Transform là ánh xạ, các hàm X_if là các bộ lọc, std :: tích lũy là gập / giảm

tương tự như vậy, bạn có thể tranh luận rằng chính các container là đơn nguyên

  • khởi tạo mẫu là một kiểu xây dựng
  • các trình tự ít nhất có các hàm tạo đơn vị, ví dụ vector<string>(1,"Foo")
  • fmap là std :: Transform
  • liên kết và / hoặc tham gia có thể thực hiện được (mặc dù không được cung cấp ngoài hộp)
  • bất kỳ triển khai hợp lý nào của ràng buộc / tham gia sẽ đáp ứng các luật đơn nguyên

Đối với các câu hỏi khác của bạn, các phần OO và các phần mẫu của C ++ là riêng biệt và các hàm ảo không loại trừ việc có các mẫu. Trong trường hợp của STL, thiết kế không chọn sử dụng các chức năng ảo.


Các hàm miễn phí so với các phương thức phần lớn là sự phân biệt cú pháp và ngược lại, vì chúng là các hàm không có nghĩa là chúng không hướng đối tượng, ngược lại.
Konrad Rudolph

Ngoài ra, các thuật toán có thể hoạt động, nhưng không có lý do gì để tin rằng std::vector<int>nó không hướng đối tượng.
DeadMG

3

Nó phụ thuộc vào người bạn yêu cầu định nghĩa về OOP, bởi vì OOP là một thuật ngữ được định nghĩa không rõ ràng và không có sự đồng thuận tốt về những gì cấu thành OOP và những gì không.

Từ quan điểm của người Java, câu trả lời có lẽ là không có vì các thuật toán và thư viện container của C ++ không xử lý đa hình thời gian chạy, không sử dụng kế thừa lớp và vì cú pháp không giống OOP-y.

Mặt khác, hãy hỏi một người lập trình funcional và câu trả lời có thể là có.

Dưới đây là cách Wikipedia định nghĩa OOP:

Lập trình hướng đối tượng (OOP) là một mô hình lập trình sử dụng "đối tượng" - cấu trúc dữ liệu bao gồm các trường dữ liệu và phương thức cùng với các tương tác của chúng - để thiết kế các ứng dụng và chương trình máy tính. Các kỹ thuật lập trình có thể bao gồm các tính năng như trừu tượng hóa dữ liệu, đóng gói, nhắn tin, mô đun hóa, đa hình và kế thừa. Nhiều ngôn ngữ lập trình hiện đại hiện hỗ trợ OOP, ít nhất là một tùy chọn.

Tất cả những thứ đó được nhận ra hoặc hỗ trợ trong thư viện chuẩn của C ++ và đặc biệt là trong phần liên quan đến các thùng chứa và thuật toán. Cụ thể, các thuật toán tăng cường đóng gói và trừu tượng hóa (và do đó là mô đun hóa) và là đa hình thông qua việc sử dụng các mẫu.


Ngoại trừ việc bạn nên sử dụng tính kế thừa với các thùng chứa đó, đây là một trong những tính năng chính của OOP.
sbi

1
@sbi Mình coi thừa kế là cá trích đỏ. Những gì OOP thực sự là về sự trừu tượng hóa và tái sử dụng mã, được tạo điều kiện bởi sự kế thừa. STL cung cấp cả hai. Nhưng chỉ để thỏa mãn định nghĩa Wikipedia để bức thư, STL container đang thực sự thực hiện thông qua thừa kế (mặc dù đó là tất nhiên một chi tiết thực hiện).
Konrad Rudolph

Kế thừa một tính năng chính - trở lại trước các mẫu. Bây giờ tôi không nghĩ có gì cốt lõi hơn về việc sử dụng tính kế thừa để thực hiện một sự trừu tượng hơn là sử dụng các mẫu để thực hiện sự trừu tượng hóa đó.
DeadMG

Nếu người ta nói về sự kế thừa theo thuật ngữ chung và không phải theo cách nó được định nghĩa trong cú pháp ngôn ngữ C ++, thì người ta có thể lập luận rằng vectơ <int> được kế thừa từ vectơ lớp cơ sở trừu tượng. Thông qua functor và quá tải toán tử, nó đạt được tính đa hình đặc trưng cho kiểu int.

@Lundin Đúng, nhưng đó chỉ đơn giản là sự trừu tượng của một giao diện. Đó là những gì kế thừa cũng làm, đó là lý do tại sao tôi nghĩ rằng thừa kế nên được nhấn mạnh.
Konrad Rudolph

1

Theo tôi, STL thiên về các thuật toán trên các container có thể lặp hơn là OO.

Nó định nghĩa một giao diện chung (iterator) sẽ được thực hiện để sử dụng algoritms.

Các trình lặp C / C ++ được gọi là liệt kê / liệt kê trong Java và C #

Có lẽ STL thiên về khía cạnh hơn OO.


1

Tôi đã học được rằng chức năng thành viên ảo điều chỉnh OO

Bạn đã nghe thấy điều đó ở đâu trên trái đất?

Các nguyên lý quan trọng của định hướng đối tượng là đóng gói và trừu tượng hóa. virtualchức năng chỉ là một phương tiện mà đạt được. Chúng hoàn toàn không cần thiết cho việc định hướng đối tượng thực tế. Thật vậy, một mẫu là một phương tiện hoàn toàn phù hợp. Nó có thể không phải là thừa kế, nhưng nó vẫn là một loại đa hình. Và một số lớp không yêu cầu.

Các container của thư viện Standard hoàn toàn hướng đối tượng. Họ gói gọn tất cả các chi tiết không cần thiết từ giao diện và trừu tượng hóa việc thực hiện đến mức tối đa có thể hợp lý.


Khi tôi được dạy "OO" 15 năm trước, tôi đã được dạy ba trụ cột quan trọng là đóng gói, kế thừa và đa hình.
sbi

Kế thừa và đa hình chỉ là một phương tiện cho mục tiêu cuối cùng: đóng gói và trừu tượng hóa. Chưa kể rằng trong khi các mẫu không sử dụng tính kế thừa, chúng là đa hình.
DeadMG

Vâng, nó thường được dạy, như sbi nói. Tôi đồng ý với bạn rằng đó phần lớn là cá trích đỏ.
Konrad Rudolph

-1

Bản thân việc triển khai OOP có nghĩa là không có gì cho đến khi bạn không định nghĩa "đối tượng" của bạn là gì. Nếu Đối tượng là các giá trị (không phải là các thực thể, giống như hầu hết các ngôn ngữ được gọi là OOP nhưng giả sử C ++), thì STL là OOP nếu không thì không.

Giả sử đoạn mã này:

Person a("joe");
Person b = a;

abhai đại diện của cùng một người sống hay chỉ là hai peson sống có cùng tên?

Đối tượng là gì? a, bHoặc người sống (s) mà họ đại diện?

Ngoài ra, kế thừa C ++ là một cơ chế tổng hợp kỹ thuật khác với kế thừa đối tượng (đó là một sự trừu tượng hóa). Cả hai có thể trùng khớp nếu bạn áp đặt một kỷ luật nhất định (như Đối tượng là tất cả các hướng dẫn có thể truy cập được và đều có thể thay thế - điều đó có nghĩa là tất cả các phương thức có liên quan đều là ảo) nếu không chúng có thể nhắm mục tiêu khác nhau (kế thừa C ++ không gì khác hơn là "thành phần ngầm" )

Các mẫu cũng có thể (thông qua chuyên môn hóa) cung cấp cơ chế "thay thế", dựa trên các loại tĩnh thay vì các loại động (dựa trên các hàm ảo) và theo nghĩa này - nếu một môn học tương tự được sử dụng tại thời gian biên dịch - cung cấp OOP thời gian biên dịch.

Về bản chất, không phải là các chương trình tổng hợp và gửi C ++ của chính nó là OOP hoặc biện minh cho OOP. Họ có thể làm những việc khác là tốt. OOP là một phương pháp trừu tượng để mô tả và liên kết các đối tượng với nhau. Các mối quan hệ đó có thể được ánh xạ tới kế thừa và gửi ảo nếu các loại đối tượng phụ thuộc vào thời gian thực hiện hoặc có thể được ánh xạ tới chuyên môn hóa mẫu và chuyển đổi ngầm định nếu các loại đối tượng có thể được xác định trong quá trình biên dịch. Kế thừa có thể chỉ là một trong những cách để cung cấp chuyển đổi ngầm giữa các tham chiếu và con trỏ.


Kế thừa luôn là một cơ chế tổng hợp, không chỉ trong C ++.
Konrad Rudolph

Tôi phải downvote ở đây. Ngay cả khi bỏ qua các phương thức ảo, thành phần có sự khác biệt nghiêm trọng đối với thừa kế.
DeadMG

@KonradRudolph: đúng, nhưng câu hỏi là về C ++.
Emilio Garavaglia

@DeadMG: xin lưu ý rằng ý nghĩa của thuật ngữ "thành phần" bên ngoài thuật ngữ OOP có nghĩa chính xác cũng bằng tiếng Anh. Và kế thừa (phương thức ảo riêng biệt) không gì khác hơn là "sáng tác với một thành viên giấu tên". Tôi khẳng định một cách hoàn hảo rằng các nhà tích phân OOP không thích những sự thật này, nhưng C ++ không chỉ là một ngôn ngữ và kế thừa OOP cũng như thành phần lớp không chỉ phục vụ OOP "là mối quan hệ" và "có". ...
Emilio Garavaglia

... Có một sự khác biệt giữa thuật ngữ OOP và thuật ngữ C ++. Quay trở lại thời mà C ++ không có sự hỗ trợ mô hình nào khác ngoài kế thừa và phương thức ảo (không có tempates và không lambdas), hai thuật ngữ có thể đã bị nhầm lẫn và sử dụng một từ thay thế cho một phương thức khác, nhưng hiện nay giảm việc thừa kế OOP để chỉ thực hiện OOP nguyên tắc thay thế là cố tình thiến ngôn ngữ.
Emilio Garavaglia
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.