Xoay quanh tính chất của hàm bạn Friend trong C++ [Archive] – Cộng đồng C Việt

View Full Version : Xoay quanh tính chất của hàm bạn Friend trong C++

longkungfu

Hướng đối tượng có tính chất đóng gói và che dấu, phân chi quyền hạn rõ ràng, nhưng trong C++xuất hiện yếu tố hàm bạn: Friend, điều này đị ngược lại tính chất đóng gói, bí mật của hướng đối tượng. Vì thế, mình xin hỏi có bạn nào có cách nào khác để cho 1 function, hay 1 Class khác có thể truy xuất vào các thành phần của Class này, … mà không dùng đến hàm Friend hay không?

MINH XIN CẢM ƠN.

aydada

có 1 cách mình biết là cứ public hết, thế là có thể truy xuất mà k cần friend (:#)
mà sao lại nói là hàm friend đi ngược lại tính chất đóng gói, bí mật của OOP nhỉ, mình nghĩ chính vì đóng gói, bảo mật nên mới có hàm friend chứ (:-)??

longkungfu

Cách của bạn cũng hay đấy…nhưng chẳng lẽ chúng ta cứ public mãi ư…có bạn nào có cách giải quyết hay hơn không…
Vấn đề hàm Friend đi ngược lại tính hướng đối tượng là chính xác đó bạn…Trong ngôn ngữ lập trình Java và C# đã không còn sử dụng, nói rõ là bỏ hẳn hàm Friend.. Bạn cứ nghĩ như zỵ nè: bạn có một vấn đề riêng tư không muốn bất kỳ ai xem, thâm chí là người thân gia đình, thì tại sao bạn phải cho 1 người khác là bạn của bạn biết. Nói rõ là tính chất đóng gói không bao giờ được biết, chỉ có bản thân người thiết kế mới được sửa.. và làm việc. Nếu muốn hiểu rõ hơn bạn hãy hỏi thử mọi người trong diễn đàn xem..Mình cũng đang muốn tìm hiểu có cách nào để thay thế hàm Friend trong C++ .

mp121209

Hướng đối tượng có tính chất đóng gói và che dấu, phân chi quyền hạn rõ ràng, nhưng trong C++xuất hiện yếu tố hàm bạn: Friend, điều này đị ngược lại tính chất đóng gói, bí mật của hướng đối tượng. Vì thế, mình xin hỏi có bạn nào có cách nào khác để cho 1 function, hay 1 Class khác có thể truy xuất vào các thành phần của Class này, … mà không dùng đến hàm Friend hay không?

MINH XIN CẢM ƠN.

Tất nhiên là không đi ngược lại tính đóng gói như í kiến bạn nói, bởi vì:
1. Việc lựa chọn người làm bạn với bạn là quyền ở bạn. Bạn có thể lựa chọn ai, bao nhiêu người, thậm chí không người nào. Những người lập dị vẫn thế mà. Hơn nữa, hàm bạn là do bạn lập, bạn viết, bạn quyết định quyền truy xuất thuộc tính của lớp cho nó, tức là bạn nắm quyền quyết định chia sẻ thông tin cho bạn của bạn. Bạn có thể viết một friend function rỗng, tức là có một người bạn, nhưng bạn không hề chia sẻ gì cho họ cả.
2. Nếu không dùng friend function, có thể để public các thuộc tính mở. Dùng kế thừa protected cho những thuộc tính protected và truy xuất chúng ở lớp kế thừa.

tauit_dnmd

Hướng đối tượng có tính chất đóng gói và che dấu, phân chi quyền hạn rõ ràng, nhưng trong C++xuất hiện yếu tố hàm bạn: Friend, điều này đị ngược lại tính chất đóng gói, bí mật của hướng đối tượng. Vì thế, mình xin hỏi có bạn nào có cách nào khác để cho 1 function, hay 1 Class khác có thể truy xuất vào các thành phần của Class này, … mà không dùng đến hàm Friend hay không?

A thắng đã nói cho bạn nghe rồi.

Còn “Vì thế, mình xin hỏi có bạn nào có cách nào khác để cho 1 function, hay 1 Class khác có thể truy xuất vào các thành phần của Class này, … mà không dùng đến hàm Friend hay không?”
Thì có cách đó bạn.
VD với :

class A
{
private: int x;
public: void setX(int val)
{
x=val;
}
};
int main()
{
/// làm j đó.
return 0;
}

thì thuộc tính x vẫn có thể lấy đc ở hàm main bình thường.

VoTichSu

Hướng đối tượng có tính chất đóng gói và che dấu, phân chi quyền hạn rõ ràng, nhưng trong C++xuất hiện yếu tố hàm bạn: Friend, điều này đị ngược lại tính chất đóng gói, bí mật của hướng đối tượng. Vì thế, mình xin hỏi có bạn nào có cách nào khác để cho 1 function, hay 1 Class khác có thể truy xuất vào các thành phần của Class này, … mà không dùng đến hàm Friend hay không?

MINH XIN CẢM ƠN.

Điều bạn muốn cũng đi ngược với tính chất đóng gói, bí mật của hướng đối tượng [sic]. Có khác gì hàm, class friend đâu?

nguyennam_20587

– Khái niệm friend đi ngược lại với lập trình hướng đối tượng giống như bạn nói nên trong java va C# người ta không dùng nữa tuy nhiên trong một so trường hợp bí quá thi vẫn phải dùng.
– Có hai cách để truy xuất là public hết các biến
– Hoặc tạo thành một hàn public function để return lại giá trị mình muốn
( anyway mình nghĩ như thế )

beautifulsoul84hung

Điều bạn muốn cũng đi ngược với tính chất đóng gói, bí mật của hướng đối tượng [sic]. Có khác gì hàm, class friend đâu?

😀 C++ cũng đâu phải ngôn ngữ thuần lập trình hướng đối tượng đâu bạn. Nó là ngôn ngữ lai. Có một câu nói của ai đó mình thấy rất hay. Cuộc sống luôn luôn có chọn bạn
^^. Ngôi nhà tất nhiên của gia đình mình. Nhưng ko cho bạn vào chơi thì ko thể gọi là nhà (:)) (_ _+)

VoTichSu

😀 C++ cũng đâu phải ngôn ngữ thuần lập trình hướng đối tượng đâu bạn. Nó là ngôn ngữ lai. Có một câu nói của ai đó mình thấy rất hay. Cuộc sống luôn luôn có chọn bạn
^^. Ngôi nhà tất nhiên của gia đình mình. Nhưng ko cho bạn vào chơi thì ko thể gọi là nhà (:)) (_ _+)

Bạn chưa nghe qua câu “tin bạn mất vợ, tin bợm mất bò” hay sao?

(đùa chơi thôi – bạn nên nhìn kỹ lại xem tôi có chống dùng friend đâu? chủ đề hỏi làm cách nào để không dùng friend, và chính tôi nói các đề nghị của chủ đều phá vỡ vòng rào đóng gói hết!)

beautifulsoul84hung

Bạn chưa nghe qua câu “tin bạn mất vợ, tin bợm mất bò” hay sao?

(đùa chơi thôi – bạn nên nhìn kỹ lại xem tôi có chống dùng friend đâu? chủ đề hỏi làm cách nào để không dùng friend, và chính tôi nói các đề nghị của chủ đều phá vỡ vòng rào đóng gói hết!)

Ờ sorry trích dẫn nhầm ^^! Định trích dẫn của chủ thớt
Mình cũng có câu: “Dùng thì phải tin. Nếu ko tin tốt nhất ko dùng ^^”

kidkid

Hướng đối tượng có tính chất đóng gói và che dấu, phân chi quyền hạn rõ ràng, nhưng trong C++xuất hiện yếu tố hàm bạn: Friend, điều này đị ngược lại tính chất đóng gói, bí mật của hướng đối tượng. Vì thế, mình xin hỏi có bạn nào có cách nào khác để cho 1 function, hay 1 Class khác có thể truy xuất vào các thành phần của Class này, … mà không dùng đến hàm Friend hay không?

Bạn có thể làm các setter & getter, các IDE hỗ trợ việc tạo những setter & getter cho property 1 cách nhanh chóng. Bạn hoàn toàn có thể ko dùng friend trong C++.

Tuy nhiện theo mình thì friend có những lúc rất hữu dụng, ví dụ cho việc testing. Khi lớp thực hiện testing hoàn toàn có quyền truy xuất vào các thuộc tính bảo vệ.

Hoặc trong những tình huống cần xử lý runtime, ví dụ, bạn có đối tượng A & trong A có phương thức setParent(obj* parent), lúc này parent phải có quyền truy xuất đến các phương thức & thuộc tính bảo về của child, bạn sẽ xử lý như thế nào ?

Các bạn nên dừng lại những cuộc tranh cãi ko cần thiết & tìm cho mình 1 solution, những thứ còn lại sẽ đến khi các bạn làm thực tế.

namdh

Tính đóng gói trong OOP không phải để hỗ trợ việc bảo mật, chẳng có gì liên quan đến bảo mật ở đây cả. Nó chỉ giúp hạn chế việc truy cập một cách không cần thiết, kiểu như “cái này mọi người không cần quan tâm nên tôi cất đi”, mục đích để giảm thiểu việc sai sót do sử dụng đối tượng không đúng cách hoặc gây side-effect.
Việc chọn ai là friend hoàn toàn nằm trong tầm kiểm soát của người tạo lớp, cũng như việc chọn ai là private, ai là public, nếu không thích thì không dùng, có gì đâu???

tuancho91

có 1 cách mình biết là cứ public hết, thế là có thể truy xuất mà k cần friend (:#)
mà sao lại nói là hàm friend đi ngược lại tính chất đóng gói, bí mật của OOP nhỉ, mình nghĩ chính vì đóng gói, bảo mật nên mới có hàm friend chứ (:-)??

mình nghĩ là nếu public hết thì class sẽ giống như struct rồi còn gì(?)

cobala_1993

dùng hàm friend thì để làm j nhỉ? mionhf chănngr hiểu j cả, và khai báo nó thế nào nhỉ(:=(|)

beautifulsoul84hung

dùng hàm friend thì để làm j nhỉ? mionhf chănngr hiểu j cả, và khai báo nó thế nào nhỉ(:=(|)

Không hiểu thì tốt nhất nên tìm tài liệu đọc thật kĩ là ok. Nhưng mình có thể giải thích qua:
Hàm friend là một hàm bình thường (Chú ý: hàm bình thường. Không nên nghĩ gì tới các hàm của class)
Có thêm chữ friend ở đằng trước và đặt trong khai báo phương thức của class để xác nhận rằng:
“Hàm này là bạn của class”: (Có chữ friend ở trước. prototype nằm trong class)
===> Lúc này hàm bình thường nhưng lại có thể sử dụng dữ liệu của lớp

VoTichSu

Tính đóng gói trong OOP không phải để hỗ trợ việc bảo mật, chẳng có gì liên quan đến bảo mật ở đây cả. Nó chỉ giúp hạn chế việc truy cập một cách không cần thiết, kiểu như “cái này mọi người không cần quan tâm nên tôi cất đi”, mục đích để giảm thiểu việc sai sót do sử dụng đối tượng không đúng cách hoặc gây side-effect.
Việc chọn ai là friend hoàn toàn nằm trong tầm kiểm soát của người tạo lớp, cũng như việc chọn ai là private, ai là public, nếu không thích thì không dùng, có gì đâu???

Giải thích như trên là đúng rồi đó.

Nhiều bạn thấy từ “bảo mật”, cho rằng nó phải là cái gì ghê gớm lắm. Thật sự ra tính chất này chủ yếu là để tách biệt cách thiết kế của lớp ra khỏi code sử dụng lớp

Tại sao lại phải tách biệt cách thiết kế của lớp?

vd tôi có lớp LopA, trong đó có trường array_cái_gì_đó truongRiengCuaLopA

nếu tôi đặt public array_cái_gì_đó truongRiengCuaLopA, thì tất cả các code sử dụng lớp LopA đều có quyền truy cập truongRiengCuaLopA và tất các các code này đều được viết để chấp nhận truongRiengCuaLopA là một array_cái_gì_đó.

Vì lý do nào đó, một ngày nọ, tôi thấy đặt truongRiengCuaLopA là kiểu vector_cái_gì_đó thì sẽ hoạt động hữu hiệu hơn. Lúc ấy, tôi phải tìm tất cả các code ngoài LopA và có liên quan đến truongRiengCuaLopA để chỉnh sửa chúng? Gặp một lớp quan trọng, tôi có thể có hàng trăm modules để sửa –> nếu có “đóng gói và bảo mật” thì công việc của tôi giản dị hơn nhiều.

Nếu tôi đã đặt truongRiengCuaLopA từ đầu là private và dùng hàm public Get/Set_array_cái_gì_đó để truy cập theo dạng array_cái_gì_đó thì bất cứ lúc nào cần đổi kiểu của truongRiengCuaLopA, tôi chỉ việc tỉnh bơ đổi kiểu và viết lại hàm Get/Set_array_cái_gì_đó. Tất cả các code trước đây làm việc với LopA vẫn vui vẻ chạy bình thường, bởi vì chúng không hề biết đến truongRiengCuaLopA. Hàm Get/Set_array_cái_gì_đó vẫn vui vẻ cho chúng truy cập cái array_cái_gì_đó.

Nếu LopA của tôi có hàm friend FriendCuaLopA thì tôi chỉ việc xem hàm này có đề cập đến truongRiengCuaLopA hay không, nếu có thì chỉnh lại. Đóng gói và bảo mật vẫn được gìn giữ.

Tóm lại bằng nguyên tắc sau: một lần cải tiến class, người ta phải tìm tất cả các public members và tìm tất cả các code có liên quan đến chúng để chỉnh sửa lại. Vì vậy class càng ít public members thì càng dễ cải tiến. Hàm/lớp friend tuy có thể truy cập các private members của class nhưng chỉ trong phạm vi code của hàm/lớp này nên vẫn dễ chỉnh sửa.

beautifulsoul84hung

Từ “Bảo mật” Khá hay. Mình thích 2 từ này và sách nó cũng viết thế 😀
Bảo mật không hoàn toàn là che dấu giữa người với người. Bảo mật còn là che dấu với các hàm

Ví dụ như trong thừa kế. Tôi chả cần biết cha tôi là thằng nào. Tôi chỉ cần biết interface là ok 😀
Nhiều khi nghĩ cha với con thì cần gì phải che dấu. Nhưng bây giờ bọn con nó nghịch lắm. Nhỡ đâu tùy hứng lên sửa đổi lung tung thì biết thế nào đc =))
Hoặc là che đi những cái gì mà người khác không quan tâm. Ví dụ như tôi chả thích nuôi cá cảnh mà tôi đi nuôi cá chó cá mèo .. (xấu ><) 😀 —-> Người khác không thích xem thì tốt nhất là che đi cho đỡ vướng mắt =))

Hoặc là khi làm một project với nhau. Nhiều khi chả muốn cho nhau xem thì che đi (mặc dầu rất dễ để biết). Ví dụ như các class đã có sẵn. Ta chỉ biết interface mà thôi.

còn phần này của votichsu mình không hoàn toàn đồng ý 😀

Hàm Get/Set_array_cái_gì_đó vẫn vui vẻ cho chúng truy cập cái array_cái_gì_đó.

Mình dùng java thấy rất nhiều hàm không sử dụng qua get (do thói quen 😀 – Có thể là thói quen của mình _ _! – Nhưng mình thấy nhiều class mẫu cũng thế :D). Còn C++ thì …………………… 😀

namdh

Từ “Bảo mật” Khá hay. Mình thích 2 từ này và sách nó cũng viết thế 😀

Sách nó dùng từ security à? Hay là sách của người Việt viết?

VoTichSu

Java hay csharp, vb.net gì cũng vậy. Khái niệm trừu tượng hóa và gói gọn dữ liệu – không phơi bày cách chứa dữ liệu cứng (data abstraction và encapsulation) vẫn là căn bản của hướng đối tượng.

Hàm Get/Set_Cái_Gì_Đó vẫn vui vẻ cho phép truy cập Array_Cái_Gì_Đó

Câu này có nghĩa là nếu class đổi cách chứa dữ liệu từ array sang thành vector thì code hai hàm trên sẽ được chỉnh sửa lại để trả về/nhận tham số là array nhưng chứa bên trong class lại là vector. Vì protocol của hai hàm này không hề thay đổi nên tất cả các code dùng class này không cần phải thay đổi theo – code gọi hàm theo kiểu nối trước (early binding) hay nối sau (late binding) qua bảng ảo đều được. Tóm lại, các code gọi hàm không cần biết dữ liệu đó được chứa như thế nào bên trong class; chúng chỉ cần biết lúc nhập thì là một array và lúc gọi ra thì cũng là một array. Cái đẹp của đóng gói là chỗ đó.

Tương tự như vậy, các code sử dụng hàm friend của lớp không cần lý tới việc lớp có thay đổi thiết kế hay không. Đối với chúng, nếu hàm friend này chưa thay đổi protocol thì còn xài được. Như vậy tuy hàm friend có đi xuyên qua hàng rào private của lớp nhưng không hề để cho code bên ngoài lợi dụng việc “xuyên hàng rào” này. Vấn đề “bảo mật” vẫn được bảo đảm.

beautifulsoul84hung

Sách nó dùng từ security à? Hay là sách của người Việt viết?

Đương nhiên là các tác giả người việt viết :D. Người tây biết tiếng việt viết sách tiếng việt rất ít 😀
Lập trình lại càng không (8-)>

@votichsu: Mình không phản đối điều bạn nói. Chỉ là phương thức gọi phương thức nhiều khi không được áp dụng. Mà người ta hay sử dụng trực tiếp các thành phần dữ liệu luôn. Nói về protocol thì chưa chắc. ví dụ như int a = get… ();
Giả sử như dữ liệu chuyển từ int sang string thì tất nhiên a cũng phải chuyển đổi cho phù hợp với protocol của get …. ();

VoTichSu

Chỉ là phương thức gọi phương thức nhiều khi không được áp dụng. Mà người ta hay sử dụng trực tiếp các thành phần dữ liệu luôn.

Người thiết kế lớp chỉ cho phép sử dụng trực tiếp thành phần dữ liệu khi dữ liệu rất đơn giản. Vì dd này chủ yếu chỉ thấy bài tập SVHS cho nên ít gặp qua các trường hợp dữ liệu phức tạp.

Nói về protocol thì chưa chắc. ví dụ như int a = get… ();

Chắc chắn, một lập trình viên có kinh nghiệm luôn luôn thiết kế loại trả về của một phương thức rất kỹ càng. Bởi vì ai cũng biết tham số có thể dùng để viết hàm chồng chứ thể loại trả về không dùng được.

Chuyện một hàm get trước đây trả về một thể loại, sau này bị chỉnh sửa thành một thể loại khác là chuyện chỉ có LTV vụng về mới làm. Nếu cần thì người ta thừa kế hoặc viết hàm chồng chứ không bao giờ đổi code kiểu này. Chính đây mới là cái ưu điểm của hàm get đối với lấy dữ liệu thẳng từ trường public; nếu lấy thằng thì mới bị kẹt int a = LopNaoDo.truongTruocDayLaIntBayGioLaString; trong khi đó int a = LopNaoDo.GetTruongTruocDayLaIntBayGioLaString() chẳng sao cả nếu trong hàm Get ta sửa code để nó tự đổi string thành int.

Cái này chính Java cũng làm vậy!

tb khi nói chuyện chỉnh sửa code, ta nói chuyện đề án đã đi được khá sâu, lớp đã viết hàng trăm cái; hoặc phần mềm đã đưa vào sử dụng rồi; hoặc lớp sử dụng lâu rồi và đem ra dùng lại cho đề án kế (code reuse). Chứ còn mới vào code thì chỉnh sửa thoải mái.

beautifulsoul84hung

Người thiết kế lớp chỉ cho phép sử dụng trực tiếp thành phần dữ liệu khi dữ liệu rất đơn giản. Vì dd này chủ yếu chỉ thấy bài tập SVHS cho nên ít gặp qua các trường hợp dữ liệu phức tạp.

Chắc chắn, một lập trình viên có kinh nghiệm luôn luôn thiết kế loại trả về của một phương thức rất kỹ càng. Bởi vì ai cũng biết tham số có thể dùng để viết hàm chồng chứ thể loại trả về không dùng được.

Chuyện một hàm get trước đây trả về một thể loại, sau này bị chỉnh sửa thành một thể loại khác là chuyện chỉ có LTV vụng về mới làm. Nếu cần thì người ta thừa kế hoặc viết hàm chồng chứ không bao giờ đổi code kiểu này. Chính đây mới là cái ưu điểm của hàm get đối với lấy dữ liệu thẳng từ trường public; nếu lấy thằng thì mới bị kẹt int a = LopNaoDo.truongTruocDayLaIntBayGioLaString; trong khi đó int a = LopNaoDo.GetTruongTruocDayLaIntBayGioLaString() chẳng sao cả nếu trong hàm Get ta sửa code để nó tự đổi string thành int.

Cái này chính Java cũng làm vậy!

tb khi nói chuyện chỉnh sửa code, ta nói chuyện đề án đã đi được khá sâu, lớp đã viết hàng trăm cái; hoặc phần mềm đã đưa vào sử dụng rồi; hoặc lớp sử dụng lâu rồi và đem ra dùng lại cho đề án kế (code reuse). Chứ còn mới vào code thì chỉnh sửa thoải mái.

Có sự khác nhau gì giữa sinh viên và người đi làm à ? 😀 Mình đang đi học
Ở đây nói tới người làm chứ không nói tới người sử dụng !

]Người thiết kế lớp chỉ cho phép sử dụng
Cái này bạn viết đâu có giống cái mình nói

int a = LopNaoDo.GetTruongTruocDayLaIntBayGioLaString()

int a = get… ();

VoTichSu

Vấn đề đi xa quá rồi !

namdh

He he, không hiểu sao tự nhiên thấy ko muốn tranh luận nữa… =))