C++ —— 模板类与友元

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

  • 非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内实现。
  • 约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数。
  • 非约束模板友元:模板类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。(实际开发Y一般不用)

示例代码:

#include <iostream>
using namespace std;

template <class T1, class T2>
class AA {
private:
    T1 m_x;
    T2 m_y;
public:
    // friend void show();
    AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};

AA<int, string> a(123, "哈哈哈");

void show() {
    cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}

int main() {
    show();

    return 0;
}

上面这段示例代码,编译会报错,原因在于:不可以在类的外部访问类的私有成员。把代码中的注释:// friend void show();取消,把全局函数show()设置为模板类AA友元函数如果忘记友元知识点,点击查看),即可成功编译运行,结果如下:

x = 123, y = 哈哈哈

这种为模板类设置友元函数的方法,在语法上没有任何问题。但是,要用模板类创建全局对象:AA<int, string> a(123, "哈哈哈");这种写法略显笨拙。

#include <iostream>
using namespace std;

template <class T1, class T2>
class AA {
private:
    T1 m_x;
    T2 m_y;

public:
    friend void show(const AA<int, string>& a);
    AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};

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

int main() {
    AA<int, string> a(666, "哈哈哈");
    show(a);

    return 0;
}

运行结果如下:

x = 666, y = 哈哈哈

现在模板类AA再创建一个对象b,数据类型改为charAA<char, string> b('x', "嘿嘿嘿");用当前的代码肯定会报错,因为数据类型不匹配。此时,重载一个show()函数即可。代码如下:

#include <iostream>
using namespace std;

template <class T1, class T2>
class AA {
private:
    T1 m_x;
    T2 m_y;

public:
    friend void show(const AA<int, string>& a);
    friend void show(const AA<char, string>& a);
    AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};

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

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

int main() {
    AA<int, string> a(666, "哈哈哈");
    show(a);
    AA<char, string> b('x', "嘿嘿嘿");
    show(b);

    return 0;
}

运行结果如下:

x = 666, y = 哈哈哈
x = x, y = 嘿嘿嘿

目前这种方式可以解决问题,但是要为模板类的每一个实例化版本都准备一个友元函数。

非模板友元

C++提供了一种解决方案:利用模板类的参数,自动生成友元函数。代码如下:

#include <iostream>
using namespace std;

template <class T1, class T2>
class AA {
private:
    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 << "x = " << a.m_x << ", y = " << a.m_y << endl;
    }
};

int main() {
    AA<int, string> a(555, "哈哈哈");
    show(a);
    AA<char, string> b('w', "嘿嘿嘿");
    show(b);

    return 0;
}

其实就是把show()函数的定义放到模板类内部,前面加一个friend关键字修饰,再把参数类型换成通用参数类型T1T2。运行结果如下:

x = 555, y = 哈哈哈
x = w, y = 嘿嘿嘿

注意,虽然编译器利用模板参数帮助我们生成了友元函数,但是friend void show(const AA<T1, T2>& a)不是模板函数。可以通过编译下面这段代码,证明这一点:

#include <iostream>
using namespace std;

template <class T1, class T2>
class AA {
private:
    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 << "x = " << a.m_x << ", y = " << 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 << "x = " << a.m_x << ", y = " << a.m_y << endl;
}

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

int main() {
    AA<int, string> a(555, "哈哈哈");
    show(a);
    AA<char, string> b('w', "嘿嘿嘿");
    show(b);

    return 0;
}

此段代码编译会报错,编译器会告诉你出现了重定义。原因就是:friend void show(const AA<T1, T2>& a)并不是函数模板。这对写程序有什么影响?如果想为某种数据创建特别版本的友元函数(具体化),这种方法是做不到的。还有,用这种方法生成的友元函数只能用于这个模板类,不能用于其它模板类。

约束模板友元

这种友元函数模板是模板函数,可用于多个模板类,可以具体化
为模板类AA设置友元函数的步骤如下:

  1. 在模板类的定义前面,声明友元函数模板。目的是为了让模板类AA知道友元函数模板的存在。
  2. 在模板类中,再次声明友元函数模板。目的是为了让编译器知道需要实例化的友元函数模板。
  3. 友元函数模板的定义。

示例代码如下:

#include <iostream>
using namespace std;

// 1.在模板类的定义前面,声明友元函数模板。目的是为了让模板类AA知道友元函数模板的存在。
template <typename T>
void show(T& a);

template <class T1, class T2>
class AA {
    friend void show<> (AA<T1, T2>& a); // 2.在模板类中,再次声明友元函数模板。
    // 目的是为了让编译器知道需要实例化的友元函数模板。
    T1 m_x;
    T2 m_y;

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

template <typename T> // 3.友元函数模板的定义。
void show(T& a) {
    cout << "通用版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}

// 友元函数是函数模板,可以有具体化版本。
template <> // 友元函数模板的具体化
void show(AA<int, string>& a) {
    cout << "具体化版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}

int main() {
    AA<int, string> a(999, "hi~");
    show(a);
    AA<char, string> b('q', "hello");
    show(b);

    return 0;
}

运行结果如下:

具体化版本 x = 999, y = hi~
通用版本 x = q, y = hello

非约束模板友元

示例代码如下:

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 << "具体版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}

int main() {
    AA<int, string> a(000, "hi~");
    show(a);
    AA<char, string> b('v', "hello");
    show(b);

    return 0;
}

运行结果如下:

具体版本 x = 0, y = hi~
通用版本 x = v, y = hello

感谢浏览,一起学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值