Trong bài này, bạn sẽ được học cách tạo hàm bạn và lớp bạn trong C++, và cách sử dụng chúng hiệu quả trong chương trình của bạn.
Một trong những định nghĩa quan trọng của OOP là che giấu dữ liệu, nghĩa là hàm không phải thành viên sẽ không thể truy xuất dữ liệu private hoặc protected của một đối tượng.
Nhưng, đôi khi sự giới hạn này sẽ khiến lập trình viên phải viết đoạn mã nguồn dài và phức tạp. Vì thế, có một cơ chế dựng sẵn trong lập trình C++ cho phép truy xuất dữ liệu private hoặc protected từ các hàm không phải thành viên.
Điều này được thực hiện thông qua hàm bạn hoặc lớp bạn.
Hàm bạn trong C++
Một hàm được định nghĩa là hàm bạn sẽ có thể truy xuất dữ liệu private và protected của một lớp.
Trình biên dịch sẽ biết một hàm là hàm bạn thông qua từ khóa friend.
Để truy xuất dữ liệu, lời khai báo hàm bạn nên được đặt bên trong thân của lớp (có thể nằm ở bất cứ đâu bên trong lớp, dù ở khu vực private hay public) bắt đầu với từ khóa friend.
Khai báo hàm bạn trong C++
class class_name
{
... .. ...
friend return_type function_name(argument/s);
... .. ...
}
Giờ bạn có thể định nghĩa hàm bạn như một hàm thông thường để truy xuất dữ liệu của lớp. Không có từ khóa friend được sử dụng khi định nghĩa hàm.
class className
{
... .. ...
friend return_type functionName(argument/s);
... .. ...
}
return_type functionName(argument/s)
{
... .. ...
// dữ liệu private và protected của lớp className có thể
// được truy xuất bởi hàm này vì nó là hàm bạn của lớp className.
... .. ...
}
Ví dụ 1: Cách hoạt động của hàm bạn
/* Chương trình C++ mô tả hoạt động của hàm bạn.*/
#include <iostream>
using namespace std;
class Distance
{
private:
int meter;
public:
Distance(): meter(0) { }
//hàm bạn
friend int addFive(Distance);
};
// định nghĩa hàm bạn
int addFive(Distance d)
{
//truy xuất dữ liệu private từ hàm không phải thành viên
d.meter += 5;
return d.meter;
}
int main()
{
Distance D;
cout<<"Distance: "<< addFive(D);
return 0;
}
Đầu ra
Distance: 5 |
Ở đây, hàm bạn addFive() được khai báo trong lớp Distance. Vì thế, dữ liệu private meter có thể được truy xuất từ hàm này.
Mặc dù ví dụ này đưa ra ý tưởng về định nghĩa hàm bạn, nhưng nó không chỉ ra bấy kỳ ý nghĩa sử dụng nào.
Một cách sử dụng có ý nghĩa hơn đó là khi bạn cần thao tác trên các đối tượng của hai lớp khác nhau. Đó là khi hàm bạn có thể thực sự hữu dụng.
Bạn hoàn toàn có thể thao tác trên hai đối tượng của các lớp khác nhau mà không cần sử dụng hàm bạn, nhưng chương trình sẽ trở nên dài, phức tạp và khó hiểu.
Ví dụ 2: Cộng các thành viên của hai lớp khác nhau sử dụng hàm bạn
#include <iostream>
using namespace std;
// khai báo trước
class B;
class A {
private:
int numA;
public:
A(): numA(12) { }
// khai báo hàm bạn
friend int add(A, B);
};
class B {
private:
int numB;
public:
B(): numB(1) { }
// khai báo hàm bạn
friend int add(A , B);
};
// hàm add() là hàm bạn của lớp A và B
// có thể truy xuất biến thành viên numA và numB
int add(A objectA, B objectB)
{
return (objectA.numA + objectB.numB);
}
int main()
{
A objectA;
B objectB;
cout<<"Sum: "<< add(objectA, objectB);
return 0;
}
Đầu ra
Sum: 13 |
Trong chương trình này, lớp A và B được khai báo add() là một hàm bạn. Vì thế, hàm này có thể truy xuất dữ liệu private của cả hai lớp.
Ở đây, hàm add() sẽ cộng hai biến private numA và numB của hai đối tượng objectA và objectB, và trả về cho hàm main().
Để giúp chương trình chạy đúng, một tiền khai báo (forward delcaration) của lớp B nên được đưa ra giống như ví dụ trên.
Đó là bởi vì lớp B được tham chiếu tới trong lớp A ở đoạn mã: friend int add(A, B);.
Lớp bạn trong lập trình C++
Tương tự, giống như trường hợp hàm bạn, một lớp cũng có thể trở thành bạn của một lớp khác sử dụng từ khóa friend. Ví dụ:
... .. ...
class B;
class A
{
// lớp B là một lớp bạn của lớp A
friend class B;
... .. ...
}
class B
{
... .. ...
}
Khi một lớp trở thành một lớp bạn, mọi hàm thành viên của lớp đó đều trở thành hàm bạn.
Trong chương trình này, mọi hàm thành viên của lớp B sẽ trở thành hàm bạn của lớp A. Vì vậy, bất kỳ hàm thành viên nào của lớp B cũng có thể truy xuất vào dữ liệu private và protected của lớp A. Nhưng hàm thành viên của lớp A không thể truy xuất dữ liệu của lớp B.
Nên nhớ, mối quan hệ bạn trong C++ chỉ mang ý nghĩa cho phép, không có nghĩa là chiếm đoạt.