在 C++11 之前,friend 关键字主要用于授予类或者函数访问另一个类的私有和受保护成员的权限。C++11 对 friend 语法进行了扩展,主要体现在允许 friend 声明一个模板实例化,这一特性增强了代码的灵活性和可维护性。下面将详细介绍 C++11 扩展的 friend 语法。
1. C++11 之前的 friend 语法回顾
在 C++11 之前,friend 可以用来声明一个普通类、普通函数或者成员函数为另一个类的友元。
1.1 友元函数
#include <iostream>
class Rectangle {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
// 声明友元函数
friend int area(const Rectangle& rect);
};
// 友元函数的定义
int area(const Rectangle& rect) {
return rect.width * rect.height;
}
int main() {
Rectangle rect(3, 4);
std::cout << "Area: " << area(rect) << std::endl;
return 0;
}
在上述代码中,area 函数被声明为 Rectangle 类的友元函数,因此它可以访问 Rectangle 类的私有成员 width 和 height。
1.2 友元类
#include <iostream>
class Rectangle {
private:
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
// 声明友元类
friend class RectanglePrinter;
};
class RectanglePrinter {
public:
void printArea(const Rectangle& rect) {
std::cout << "Area: " << rect.width * rect.height << std::endl;
}
};
int main() {
Rectangle rect(3, 4);
RectanglePrinter printer;
printer.printArea(rect);
return 0;
}
这里,RectanglePrinter 类被声明为 Rectangle 类的友元类,所以 RectanglePrinter 类的成员函数可以访问 Rectangle 类的私有成员。
2. C++11 扩展的 friend 语法:friend 模板实例化
C++11 允许在 friend 声明中直接使用模板实例化,这使得我们可以将特定的模板实例声明为友元。例如:
#include <iostream>
// 模板类声明
template <typename T>
class FriendTemplate;
// 目标类
class MyClass {
private:
int data;
public:
MyClass(int value) : data(value) {}
// 声明模板实例为友元
friend class FriendTemplate<int>;
};
// 模板类定义
template <typename T>
class FriendTemplate {
public:
void printData(const MyClass& obj) {
std::cout << "Data: " << obj.data << std::endl;
}
};
int main() {
MyClass obj(42);
FriendTemplate<int> ft;
ft.printData(obj);
return 0;
}
在上述代码中,MyClass 类将 FriendTemplate<int> 这个模板实例声明为友元。因此,FriendTemplate<int> 类的成员函数 printData 可以访问 MyClass 类的私有成员 data。
代码解释
- 模板类声明:首先,需要对模板类 FriendTemplate 进行前向声明,这样 MyClass 类才能知道 FriendTemplate 是一个模板类。
- 友元声明:在 MyClass 类中,使用 friend class FriendTemplate<int>; 声明 FriendTemplate<int> 为友元。注意,这里明确指定了模板参数为 int,只有 FriendTemplate<int> 这个特定的实例才能访问 MyClass 的私有成员。
- 模板类定义:在 FriendTemplate 类的定义中,其成员函数 printData 可以访问 MyClass 的私有成员 data,因为 FriendTemplate<int> 是 MyClass 的友元。
3. 扩展 friend 语法的优势
- 精细控制访问权限:通过将特定的模板实例声明为友元,可以更精确地控制哪些类或函数能够访问目标类的私有成员,提高了代码的安全性。
- 增强代码灵活性:在模板编程中,这种扩展的 friend 语法使得我们可以根据不同的模板参数实例化来灵活地授予友元权限,避免了将整个模板类都声明为友元带来的不必要的访问权限开放。
4. 注意事项
- 模板实例化的明确性:在 friend 声明中,必须明确指定模板参数,以确定具体的模板实例。例如,friend class FriendTemplate<int>; 明确指定了 int 作为模板参数。
- 作用域问题:友元关系是单向的,并且只在声明友元的类中有效。FriendTemplate<int> 可以访问 MyClass 的私有成员,但 MyClass 不能自动访问 FriendTemplate<int> 的私有成员。