Template 基础篇-模板与友元
Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第四部分。
类友元
类模板之间、类模板与普通类之间共有三种友元的形式:
友元 | 普通类 | 类模板 |
---|---|---|
普通类 | 类模板友元 | |
类模板 | 类友元 | 类模板的类模板友元 |
普通类的类模板友元
一对一关系
可以将类模板的一个实例声明为普通类的友元。
template <typename T>
class Pal {
public:
static void Call(T& t) {
t.show();
}
};
class HasFriend {
//只有Pal<HasFriend>才是友元,其他实例不行。
//注意这里将未完整定义的class放入了模板。
friend class Pal<HasFriend>;
private:
void show() {
cout << "Calling private method" << endl;
}
};
HasFriend hf;
Pal<HasFriend>::Call(hf); //Pal<HasFriend>是HasFriend的友元
一对多关系
也可以把类模板声明为类的友元模板,这意味着这个类模板的所有实例都是类的友元。声明时要使用template和class关键字(这一点和模板的模板参数很像)。
template <typename T> class Pal;
class HasFriend {
template <typename T> friend class Pal; //注意这里的template、class关键字与friend的前后关系
private:
void show() {
cout << "Calling private method" << endl;
}
};
template <typename T>
class Pal {
public:
static void Call(HasFriend& hf) {
hf.show();
}
};
HasFriend hf;
Pal<void>::Call(hf); //Pal<void>是HasFriend的友元
Pal<int>::Call(hf); //Pal<int>是HasFriend的友元
类模板的普通类友元
可以将一个普通类声明为类模板的友元。
class Pal;
template <typename T>
class HasFriend {
friend class Pal;
private:
void show() {
cout << "Calling private method" << endl;
}
};
class Pal {
public:
static void Call() {
HasFriend<int> hf;
hf.show();
}
};
Pal::Call(); //Pal是HasFriend<int>的友元
类模板的类模板友元
一对一关系
可以通过共享类型参数T,在类模板与类模板友元之间达成一对一的关系。
template <typename T>
class Pal;
template <typename T>
class HasFriend {
friend class Pal<T>;
private:
void show() {
cout << "Calling private method" << endl;
}
};
template <typename T>
class Pal {
public:
static void Call() {
HasFriend<T> hf;
hf.show();
}
};
Pal<int>::Call(); //Pal<int>是HasFriend<int>的友元
多对多关系
为类模板友元声明一个不同的类型参数,可以达到多对多关系,也就是说template B的所有实例都是template A的所有实例的友元。
template <typename T>
class Pal;
template <typename T>
class HasFriend {
template <typename U> friend class Pal;
private:
void show() {
cout << "Calling private method" << endl;
}
};
template <typename T>
class Pal {
public:
static void Call() {
HasFriend<int> hf;
hf.show();
}
};
Pal<double>::Call(); //Pal<double>是HasFriend<int>的友元
Pal<void>::Call(); //Pal<void>是HasFriend<int>的友元
函数友元
类(类模板)与函数(函数模板)之间共有三种友元的形式:
友元 | 普通函数 | 函数模板 |
---|---|---|
普通类 | 函数模板友元 | |
类模板 | 函数友元 | 类模板的函数模板友元 |
普通类的函数模板友元
一对一关系
可以将函数模板的一个实例声明为普通类的友元。
template <typename T>
void call(T& t) {
t.show();
}
class HasFriend {
friend void call<HasFriend>(HasFriend&);
private:
void show() {
cout << "Calling private method" << endl;
}
};
HasFriend hf;
call(hf); //ok, void call<HasFriend>(HasFriend&)是HasFriend的友元
一对多关系
也可以把函数模板声明为类的友元模板,这意味着这个函数模板的所有实例都是类的友元。声明时注意要使用template关键字。
template <typename T, typename U>
void call(T& t, U& u) {
cout << t << endl;
u.show();
}
class HasFriend {
template <typename T, typename U> friend void call(T&, U&);
private:
void show() {
cout << "Calling private method" << endl;
}
};
HasFriend hf;
int i = 1;
call(i, hf); //void call(int&, HasFriend&)是HasFriend的友元,注意这里的类型自动推导
double d = 2.0;
call(d, hf); //void call(double&, HasFriend&)是HasFriend的友元,注意这里的类型自动推导
类模板的函数友元
可以将一个普通函数声明为类模板的友元,这样,这个普通函数就是这个类模板的所有实例的友元。
void call();
template <typename T>
class HasFriend {
friend void call();
private:
void show() {
cout << "Calling private method" << endl;
}
};
void call() {
HasFriend<int> hf1;
HasFriend<double> hf2;
hf1.show(); //ok,友元
hf2.show(); //ok,友元
}
call();
类模板的函数模板友元
一对一关系
可以通过共享类型参数T,在类模板与函数模板友元之间达成一对一的关系。
template <typename T>
void call(const T& t);
template <typename T>
class HasFriend {
friend void call<T>(const T& t);
private:
void show() {
cout << "Calling private method" << endl;
}
};
template <typename T>
void call(const T& t) {
HasFriend<T> hf;
hf.show();
}
call(1); //ok,共享同一个类型实参int
多对多关系
为函数模板友元声明一个不同的类型参数,可以达到多对多关系。
template <typename T>
void call(const T& t);
template <typename T>
class HasFriend {
template <typename U> friend void call(const U& u);
private:
void show() {
cout << "Calling private method" << endl;
}
};
template <typename T>
void call(const T& t) {
HasFriend<int> hf;
hf.show();
}
call(1.0f); //call<float>是HasFriend<int>的友元
call(2.0); //call<double>是HasFriend<int>的友元
模板参数友元
在C++11中,我们还可以将模板类型参数声明为友元。
template <typename T>
class HasFriend {
friend T; //T是HasFriend<T>的友元
private:
void show() {
cout << "Calling private method" << endl;
}
};
class Pal {
public:
static void call() {
HasFriend<Pal> hf;
hf.show();
}
};
Pal::call();