C ++ cho bạn bè hay không kết bạn


19

Tôi có một chương trình hướng đối tượng với khóa học c ++ trong học kỳ này ở trường đại học và chúng tôi đã học về các chức năng của bạn bè.

Theo bản năng, tôi không thích họ vì khả năng bỏ qua bảo mật mà Encapsulation và Data giấu cung cấp, tôi đã đọc một vài bài viết trên internet và một số người nghĩ rằng đó là một ý tưởng tốt với một số sử dụng hợp pháp.

Một chuyên gia OOP sẽ nói gì về những người bạn trong C ++? Tôi có nên lướt qua nó hay tôi nên tìm hiểu thêm về nó?


@all: Câu trả lời và nhận xét tuyệt vời, Đây là một cách tuyệt vời để học, không có cách nào tôi đã học về bạn bè trong các chi tiết như vậy trong sách giáo khoa.
nikhil

Câu trả lời:


13

Không phải lúc nào cũng thuận tiện để thực hiện tất cả các chức năng liên quan đến một thành viên lớp C ++ của lớp đó. Ví dụ, hãy tưởng tượng một triển khai của đại số vectơ với phép nhân vô hướng. Chúng tôi muốn viết:

 double a;
 Vector v, w;
 w = v * a;

Chúng ta có thể làm điều này với một chức năng thành viên:

public class Vector {
 ...
 Vector operator*(double a);
}

Nhưng chúng tôi cũng muốn viết:

w = a * v

Điều này đòi hỏi một chức năng miễn phí:

 Vector operator*(double a, Vector v)

Các friendtừ khóa được thêm vào C ++ để hỗ trợ việc sử dụng này. Hàm miễn phí là một phần của việc triển khai lớp Vector và nên được khai báo trong cùng một tiêu đề và được thực hiện trong cùng một tệp nguồn.

Tương tự như vậy, chúng ta có thể sử dụng friendđể đơn giản hóa việc thực hiện các lớp được liên kết chặt chẽ, như bộ sưu tập và trình lặp. Một lần nữa, tôi sẽ khai báo cả hai lớp trong cùng một tiêu đề và triển khai chúng trong cùng một tệp nguồn.


3
"Điều này đòi hỏi một chức năng miễn phí". Không, nó không : inline Vector operator*(double a, Vector v) { return v*a; }. Giải pháp Canonical trong thực tế.
MSalters

1
@MSalters: Điểm tốt. Tôi chọn một ví dụ nghèo. Tôi nghĩ rằng chức năng nội tuyến của bạn là một chức năng miễn phí theo định nghĩa, nhưng không yêu cầu khai báo bạn bè.
kevin cline

4
@MSalters: Điều đó chỉ hợp lệ nếu * liên quan đến giao hoán với a và v (x). Nếu các thành phần vectơ là chung (không nhất thiết là vô hướng), bạn phải giữ trật tự toán hạng
Emilio Garavaglia

Đó là lý thuyết khá. Có lẽ trường hợp không giao hoán phổ biến duy nhất sẽ là inline Vector operator*(double a, Vector v) { return -v*a; }và điều đó vẫn không cần tình bạn.
MSalters

16

Các hàm bạn bè không khác gì các hàm thành viên về mặt đóng gói. Tuy nhiên, họ có thể cung cấp các lợi thế khác - chẳng hạn như chung chung hơn, đặc biệt là khi các mẫu có liên quan. Ngoài ra, một số toán tử chỉ có thể được chỉ định là các hàm miễn phí, vì vậy nếu bạn muốn chúng có quyền truy cập thành viên, bạn phải friend.

Nó tốt hơn cho friendmột chức năng duy nhất hơn là bị buộc phải làm cho một cái gì đó bạn không muốn công khai. Điều đó có nghĩa là cả thế giới có thể sử dụng nó - thay vì chỉ một chức năng.


+1 cho các chức năng Bạn bè không khác với các chức năng thành viên về mặt đóng gói. Điều này chỉ đúng cho các chức năng thành viên công cộng mặc dù.
TheFogger

1
@TheFogger: Có thể cho rằng, bạn cũng có thể là friendmột hàm cũng là "riêng tư", chẳng hạn như chỉ được khai báo trong một TU duy nhất.
DeadMG

5

Nếu bạn đam mê những gì bạn làm, bạn sẽ học mọi thứ về C ++. Tìm hiểu những gì họ được sử dụng cho, làm thế nào để sử dụng chúng, và sau đó - và chỉ sau đó - quyết định không sử dụng chúng. Ít nhất, bạn sẽ được chuẩn bị khi đọc mã của người khác sử dụng khía cạnh này của C ++.


5

" Chuyên gia OOP sẽ nói gì ... " Điều này chủ yếu phụ thuộc vào việc anh ta là chuyên gia về C ++ như thế nào, đó là đặc điểm kỹ thuật của chính nó - không phải (và không muốn trở thành) một ngôn ngữ cho chủ nghĩa thuần túy.

OOP Zealots không sử dụng C ++ (họ thích Smalltalk và thích Java).

Các zelots lập trình chức năng không sử dụng C ++ (họ thích LISP và những người kế thừa của nó)

Hầu hết các chuyên gia OOP không thích chức năng kết bạn chỉ đơn giản vì họ muốn phần OOP của C ++ hoạt động giống như Smalltalk. Nhưng C ++ không phải là Smalltalk và họ thậm chí không thể hiểu rằng bạn bè không phá vỡ việc đóng gói , vì lý do rất đơn giản là một hàm không thể là bạn của lớp bạn mà không có lớp bạn muốn .

Và từ quan điểm "chức năng", giữa a.fn(b)fn(a,b)không có sự khác biệt ( fnbạn bè ở đâu): các bên liên quan là như nhau. Đơn giản chỉ cần, một cú pháp có thể thích hợp hơn: nếu fn là hoán về ab, fn(a,b)có lẽ là phù hợp hơn rồi a.fn(b)(. Nơi một vẻ ngoài có một "vai trò đặc biệt" rằng, trên thực tế, nó không)


1
Những người nhiệt tình của OOP Những người thích Java không hiểu OOP. Getters? Setters? Không có cú pháp đơn giản cho việc đóng cửa? Để diễn giải Alan Kay, đây không phải là cách anh ta tưởng tượng ra OOP.
Konrad Rudolph

@Konrad: Zealots được thiết lập không giới hạn. Luôn luôn có một nhiệt tâm nhiều hơn nhiệt tình hơn một nhiệt tâm nhất định.
Emilio Garavaglia

Tôi phải nói rằng tôi đã ủng hộ vì tôi thực sự thích đoạn cuối đó. Hãy làm cho nó thêm ý nghĩa hơn.
julealgon

5

"Bạn bè" có vi phạm đóng gói không?

Không nó không. "Bạn bè" là một cơ chế rõ ràng để cấp quyền truy cập, giống như thành viên. Bạn không thể (trong một chương trình tuân thủ tiêu chuẩn) cấp cho mình quyền truy cập vào một lớp mà không sửa đổi nguồn của nó.


2

Câu hỏi thường gặp về C ++ ngắn gọn:

Sử dụng một thành viên khi bạn có thể, và một người bạn khi bạn phải.

Câu hỏi thường gặp trình bày một trong những cách suy nghĩ hữu ích hơn về tình bạn:

Nhiều người nghĩ về một người bạn hoạt động như một cái gì đó bên ngoài lớp học. Thay vào đó, hãy thử nghĩ về chức năng bạn bè như một phần của giao diện chung của lớp. Hàm bạn bè trong khai báo lớp không vi phạm đóng gói nhiều hơn chức năng thành viên công cộng vi phạm đóng gói: cả hai đều có cùng thẩm quyền đối với việc truy cập các phần không công khai của lớp.

Có lẽ việc sử dụng chức năng bạn bè phổ biến nhất là quá tải << cho I / O.


0

Các hàm bạn bè được sử dụng tốt nhất cho các định nghĩa toán tử do người dùng định nghĩa. Chúng rất hữu ích trong các tình huống khác, nhưng nếu bạn thấy mình chỉ định các lớp bạn bè thường xuyên thì bạn có thể đang đi đường vòng thiết kế (chỉ cần tự kiểm tra tốt để sử dụng trong khi viết mã).

Hãy cẩn thận về tuyên bố "bảo mật" trong câu hỏi ban đầu. Công cụ sửa đổi truy cập có mặt để ngăn bạn viết mã xấu do tai nạn, giống như trình biên dịch theo cách nào đó. Các bộ sửa đổi truy cập giới hạn giao diện và phục vụ để truyền đạt các chức năng nào là quan trọng để sử dụng lớp (công khai và được bảo vệ), và các chức năng nào được tạo ra như là một phần làm cho lớp đẹp hơn cho các nhà bảo trì (riêng tư). Công cụ sửa đổi không cấu thành bảo mật ở chỗ có nhiều cách để lấy dữ liệu riêng tư. Ví dụ, lấy một con trỏ đến lớp và kích thước của nó, và đi câu cá.


-2

Các chức năng bạn bè của C ++ có liên quan chặt chẽ đến các chức năng sau:

  1. chức năng miễn phí
  2. hàm tĩnh
  3. chức năng bạn bè

Điều này có nghĩa là chúng không có con trỏ này và do đó nằm ngoài lớp / đối tượng. Mặt khác, họ thường lấy các tham số khiến chúng một lần nữa thuộc về lớp. Dưới đây là một số ví dụ làm rõ liên kết:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

Sự khác biệt duy nhất giữa các hàm tĩnh và các hàm friend là một hàm friend có thể sử dụng một vài lớp.

Sử dụng cơ chế kết bạn trong c ++ đòi hỏi các lập trình viên có kinh nghiệm khoảng 10-15 năm với cách lập trình c ++, và do đó ban đầu bạn nên tránh nó. Đó là tính năng nâng cao.


7
Và bạn bắt nguồn từ 10 - 15 năm như thế nào?
DeadMG

10-15 năm đến từ khi nó thực sự cần thiết.
tp1

3
Vì vậy, bạn tùy ý tạo ra một số, sau đó.
DeadMG

3
-1: "Bạn nên tránh nó." Mỗi tính năng của C ++ được tạo ra để giải quyết vấn đề. Khi vấn đề đó phát sinh, sử dụng các tính năng thích hợp.
kevin cline

Cảm ơn vì -1. Có một lý do cho nhận xét đó. Đoán chỉ là khái niệm khó khăn mà không phải tất cả các tính năng đều phù hợp cho người mới bắt đầu.
tp1
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.