46 CPP模板类和友元

本文详细介绍了C++中模板类的友元函数,包括非模板友元、约束模板友元和非约束模板友元。通过示例代码展示了如何使用这三种友元函数访问类的私有成员,以及它们的优缺点。特别是约束模板友元,作为最佳实践,允许为特定模板实例创建特定版本的友元函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果要访问类的私有成员,调用类的公有成员函数是唯一的办法,而类的私有成员函数则无法访问。

友元提供了另一访问类的私有成员的方案。友元有3中:

1 友元全局函数

2 友元类

3 友元成员函数。

模板类的友元函数有三类:

1 非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数。

2 约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数。

3 非约束模板友元:模板类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。(在实际开发中一般不用,因为它不科学。模板类实例化的时候,如果有n种的数据类型,就会实例化n个类出来,也会实例化n个友元函数,每个实例化的类拥有n个友元函数,这就不科学了,每个实例化的类只需要一个友元函数就行了,不需要n个,其它数据类型的友元函数和自己没有关系。)

#include "iostream"
using namespace std;

//冗余的模板友元
template <class T1, class T2>
class AA
{
    T1 m_x;
    T2 m_y;

public:
    AA(const T1 x, const T2 y) : m_x(x), m_y(y)
    {
    }
    //下面这种方案的本质,是编译器利用模板参数帮我们生成了友元函数,使用起来很方便,但是有个细节
    //编译器利用模板参数生成的友元函数,但是这个函数不是模板函数
    //编译器创建模板类实例的时候,会用这些代码生成友元函数的实体,如果把下面注释的代码打开,就会出现冲突,导致报错
    friend void show(const AA<T1, T2> &a)
    {
        cout << a.m_x << endl;
        cout << a.m_y << endl;
    }
    // friend void show(const AA<int, string> &a);
    // friend void show(const AA<char, string> &a);
};

// void show(const AA<int, string> &a)
// {
//     cout << a.m_x << endl;
//     cout << a.m_y << endl;
// }

// void show(const AA<char, string> &a)
// {
//     cout << a.m_x << endl;
//     cout << a.m_y << endl;
// }

void test()
{
    AA<int, string> aa(1, "hello");
    show(aa);

    AA<char, string> bb('a', "hello");
    show(bb);
}
int main()
{
    test();
    return 0;
}

上面代码,使用很方便,但是也有局限,如果我们想为某种数据类型创建特别版本的友元函数(具体化),这种方法是做不到的。还有就是这种方法生成的友元函数只能用于这个模板类,不能用于其它的模板类。

#include "iostream"
using namespace std;
//约束模板友元:模板实例化时,每个实例化的类对应一个友元函数
//这种友元代码比较多,不用记住,用到的时候查查就行,但是它是最好的友元方案
template <typename T>
void show(T &a); //第一步:在模板类的定义前面,声明友元函数模板

template <class T1, class T2>
class AA
{
    friend void show<>(AA<T1, T2> &a); //第二步:在模板类中,再次声明友元函数模板
    T1 m_x;
    T2 m_y;

public:
    AA(const T1 x, const T2 y) : m_x(x), m_y(y) {}
};
template <typename T>
void show(T &a)
{
    cout << "通用:x=" << a.m_x << ",y=" << a.m_y << endl;
}
template <> //第三步:具体化版本
void show(AA<int, string> &a)
{
    cout << "具体AA<int,string>:x=" << a.m_x << ",y=" << a.m_y << endl;
}

//这种友元的函数模板可以用于多个模板类
template <class T1, class T2>
class BB
{
    friend void show<>(BB<T1, T2> &a); //第二步:在模板类中,再次声明友元函数模板
    T1 m_x;
    T2 m_y;

public:
    BB(const T1 x, const T2 y) : m_x(x), m_y(y) {}
};
template <> //第三步:具体化版本
void show(BB<int, string> &a)
{
    cout << "具体BB<int,string>:x=" << a.m_x << ",y=" << a.m_y << endl;
}

void test()
{
    AA<int, string> a(2, "hello");
    show(a);

    AA<char, string> b('a', "world");
    show(b);

    BB<int, string> ba(2, "hello");
    show(ba);

    BB<char, string> bb('a', "world");
    show(b);
}
int main()
{
    test();
    return 0;
}
/* 具体AA<int,string>:x=2,y=hello
通用:x=a,y=world
具体BB<int,string>:x=2,y=hello
通用:x=a,y=world */
#include "iostream"
using namespace std;
// 非约束模板友元
template <class T1, class T2>
class AA
{
    template <typename T> friend void show(T &a);
    T1 m_x;
    T2 m_y;

public:
    AA(const T1 x, const T2 y) : m_x(x), m_y(y) {}
};

template <typename T>
void show(T &a) //通用的函数模板
{
    cout << "通用:x=" << a.m_x << ",y=" << a.m_y << endl;
}

template <>
void show(AA<int, string> &a) //函数模板的具体版本
{
    cout << "具体<int,string>:x=" << a.m_x << ",y=" << a.m_y << endl;
}

void test()
{
    AA<int, string> aa(3, "hello");
    show(aa);

    AA<char, string> bb('a', "world");
    show(bb);
}
int main()
{
    test();
    return 0;
}
具体<int,string>:x=3,y=hello
通用:x=a,y=world

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值