title | categories | tags | |||||
---|---|---|---|---|---|---|---|
C++ 模板与友元:深入解析 |
|
|
在C++中,模板(Template)和友元(Friend)是两个非常强大的特性。模板允许我们编写通用的代码,而友元则允许我们在类的外部访问类的私有成员。当这两个特性结合在一起时,可以实现非常灵活且强大的功能。本文将按照不同的场景,详细讲解模板与友元的各种结合方式。
类友元是指将一个类声明为另一个类的友元。类友元可以分为以下几种情况:
在这种关系中,普通类只将类模板的一个特定实例声明为友元。
#include <iostream>
template <typename T>
class MyTemplateClass;
// 普通类
class MyClass {
private:
int data;
public:
MyClass(int d) : data(d) {}
// 将类模板的一个实例声明为友元
friend class MyTemplateClass<int>;
};
// 类模板
template <typename T>
class MyTemplateClass {
public:
void printData(const MyClass& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyClass的私有成员
}
};
int main() {
MyClass obj(42);
MyTemplateClass<int> templateObj;
templateObj.printData(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyClass
是一个普通类,它将MyTemplateClass<int>
声明为友元。MyTemplateClass<int>
是MyTemplateClass
模板的一个实例,它可以访问MyClass
的私有成员data
。
在这种关系中,普通类将整个类模板声明为友元,这意味着类模板的所有实例都是该类的友元。
#include <iostream>
// 普通类
class MyClass {
private:
int data;
public:
MyClass(int d) : data(d) {}
// 将类模板声明为友元模板
template <typename T>
friend class MyTemplateClass;
};
// 类模板
template <typename T>
class MyTemplateClass {
public:
void printData(const MyClass& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyClass的私有成员
}
};
int main() {
MyClass obj(42);
MyTemplateClass<int> templateObj1;
MyTemplateClass<double> templateObj2;
templateObj1.printData(obj); // 输出: Data: 42
templateObj2.printData(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyClass
将MyTemplateClass
模板声明为友元模板,这意味着MyTemplateClass
的所有实例(如MyTemplateClass<int>
和MyTemplateClass<double>
)都可以访问MyClass
的私有成员。
在这种关系中,类模板将一个普通类声明为友元,这样,这个普通类就是类模板的所有实例的友元。
#include <iostream>
// 前置声明类模板
template <typename T>
class MyTemplateClass;
// 普通类
class MyFriendClass {
public:
void printData(const MyTemplateClass<int>& obj);
};
// 类模板
template <typename T>
class MyTemplateClass {
private:
T data;
public:
MyTemplateClass(T d) : data(d) {}
// 将普通类声明为友元
friend class MyFriendClass;
};
// 实现 printData 函数
void MyFriendClass::printData(const MyTemplateClass<int>& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyTemplateClass的私有成员
}
int main() {
MyTemplateClass<int> obj(42);
MyFriendClass friendObj;
friendObj.printData(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyTemplateClass
是一个类模板,它将MyFriendClass
声明为友元。MyFriendClass
可以访问MyTemplateClass
的所有实例的私有成员data
。
在这种关系中,类模板和类模板友元共享相同的类型参数 T
,从而形成一对一的关系。
#include <iostream>
template <typename U>
class MyTemplateFriendClass;
// 类模板
template <typename T>
class MyTemplateClass {
private:
T data;
public:
MyTemplateClass(T d) : data(d) {}
// 将类模板友元声明为友元
friend class MyTemplateFriendClass<T>;
};
// 类模板友元
template <typename U>
class MyTemplateFriendClass {
public:
void printData(const MyTemplateClass<U>& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyTemplateClass的私有成员
}
};
int main() {
MyTemplateClass<int> obj(42);
MyTemplateFriendClass<int> friendObj;
friendObj.printData(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyTemplateClass<T>
和MyTemplateFriendClass<U>
共享相同的类型参数T
,从而形成一对一的关系。MyTemplateFriendClass<T>
可以访问MyTemplateClass<T>
的私有成员data
。
在这种关系中,类模板友元使用不同的类型参数,从而形成多对多的关系。
#include <iostream>
// 类模板
template <typename T>
class MyTemplateClass {
private:
T data;
public:
MyTemplateClass(T d) : data(d) {}
// 将类模板友元声明为友元
template <typename U>
friend class MyTemplateFriendClass;
};
// 类模板友元
template <typename U>
class MyTemplateFriendClass {
public:
void printData(const MyTemplateClass<U>& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyTemplateClass的私有成员
}
};
int main() {
MyTemplateClass<int> obj1(42);
MyTemplateClass<double> obj2(3.14);
MyTemplateFriendClass<int> friendObj1;
MyTemplateFriendClass<double> friendObj2;
friendObj1.printData(obj1); // 输出: Data: 42
friendObj2.printData(obj2); // 输出: Data: 3.14
return 0;
}
代码分析:
MyTemplateClass<T>
将MyTemplateFriendClass<U>
声明为友元,其中U
是不同的类型参数。- 这意味着
MyTemplateFriendClass<U>
的所有实例都可以访问MyTemplateClass<T>
的所有实例的私有成员data
。
函数友元是指将一个函数声明为类的友元。函数友元可以分为以下几种情况:
在这种关系中,普通类只将函数模板的一个特定实例声明为友元。
#include <iostream>
class MyClass;
template <typename T>
void printData(const MyClass& obj);
// 普通类
class MyClass {
private:
int data;
public:
MyClass(int d) : data(d) {}
// 将函数模板的一个实例声明为友元
friend void printData<int>(const MyClass& obj);
};
// 函数模板
template <typename T>
void printData(const MyClass& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyClass的私有成员
}
int main() {
MyClass obj(42);
printData<int>(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyClass
将printData<int>
声明为友元。printData<int>
可以访问MyClass
的私有成员data
。
在这种关系中,普通类将整个函数模板声明为友元,这意味着函数模板的所有实例都是该类的友元。
#include <iostream>
// 普通类
class MyClass {
private:
int data;
public:
MyClass(int d) : data(d) {}
// 将函数模板声明为友元模板
template <typename T>
friend void printData(const MyClass& obj);
};
// 函数模板
template <typename T>
void printData(const MyClass& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyClass的私有成员
}
int main() {
MyClass obj(42);
printData<int>(obj); // 输出: Data: 42
printData<double>(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyClass
将printData
函数模板声明为友元模板,这意味着printData
的所有实例都可以访问MyClass
的私有成员。
在这种关系中,类模板将一个普通函数声明为友元,这样,这个普通函数就是类模板的所有实例的友元。
#include <iostream>
// 类模板
template <typename T>
class MyTemplateClass {
private:
T data;
public:
MyTemplateClass(T d) : data(d) {}
// 将普通函数声明为友元
friend void printData(const MyTemplateClass<T>& obj);
};
// 普通函数
void printData(const MyTemplateClass<int>& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyTemplateClass的私有成员
}
int main() {
MyTemplateClass<int> obj(42);
printData(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyTemplateClass
是一个类模板,它将printData
函数声明为友元。printData
函数可以访问MyTemplateClass
的所有实例的私有成员data
。
在这种关系中,类模板和函数模板友元共享相同的类型参数 T
,从而形成一对一的关系。
#include <iostream>
// 类模板
template <typename T>
class MyTemplateClass {
private:
T data;
public:
MyTemplateClass(T d) : data(d) {}
// 将函数模板的一个实例声明为友元
friend void printData<T>(const MyTemplateClass<T>& obj);
};
// 函数模板友元
template <typename U>
void printData(const MyTemplateClass<U>& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyTemplateClass的私有成员
}
int main() {
MyTemplateClass<int> obj(42);
printData(obj); // 输出: Data: 42
return 0;
}
代码分析:
MyTemplateClass<T>
和printData<U>
共享相同的类型参数T
,从而形成一对一的关系。printData<T>
可以访问MyTemplateClass<T>
的私有成员data
。
在这种关系中,函数模板友元使用不同的类型参数,从而形成多对多的关系。
#include <iostream>
// 类模板
template <typename T>
class MyTemplateClass {
private:
T data;
public:
MyTemplateClass(T d) : data(d) {}
// 将函数模板友元声明为友元
template <typename U>
friend void printData(const MyTemplateClass<U>& obj);
};
// 函数模板友元
template <typename U>
void printData(const MyTemplateClass<U>& obj) {
std::cout << "Data: " << obj.data << std::endl; // 访问MyTemplateClass的私有成员
}
int main() {
MyTemplateClass<int> obj1(42);
MyTemplateClass<double> obj2(3.14);
printData(obj1); // 输出: Data: 42
printData(obj2); // 输出: Data: 3.14
return 0;
}
代码分析:
MyTemplateClass<T>
将printData<U>
声明为友元,其中U
是不同的类型参数。- 这意味着
printData<U>
的所有实例都可以访问MyTemplateClass<T>
的所有实例的私有成员data
。
我们还可以将模板类型参数声明为友元。这意味着模板类型参数本身可以访问类的私有成员。
#include <iostream>
template <typename T>
class MyClass {
// 将模板类型参数 T 声明为友元
friend T;
private:
int secret;
public:
MyClass(int s) : secret(s) {}
};
// 定义一个类,它将访问 MyClass<T>::secret
class MyFriendClass {
public:
void accessSecret(MyClass<MyFriendClass>& obj) {
// 由于 MyFriendClass 被声明为 MyClass<MyFriendClass> 的友元
// 因此它可以访问 secret
std::cout << "Secret: " << obj.secret << std::endl;
}
};
int main() {
MyClass<MyFriendClass> myObj(42);
MyFriendClass friendObj;
friendObj.accessSecret(myObj);
return 0;
}
代码分析:
MyTemplateClass<T>
将模板类型参数T
声明为友元。- 这意味着
T
类型的对象可以访问MyTemplateClass<T>
的私有成员data
。
本文详细讲解了C++中模板与友元的各种结合方式,包括类友元和函数友元的不同场景。通过这些结合方式,我们可以实现非常灵活且强大的代码设计。希望本文能帮助你更好地理解C++中的模板与友元机制,并在实际编程中灵活运用。
文章合集:chongzicbo/ReadWriteThink: 博学而笃志,切问而近思 (github.com)
个人博客:程博仕
微信公众号: