首页 > 其他分享 >类模板中的友元

类模板中的友元

时间:2024-03-29 20:00:55浏览次数:22  
标签:友元 函数 Men 模板 func 友元类

1. 友元类

传统友元类的概念是:让某个类B成为另外一个类A的友元类,这样的话,类B就可以在其成员函数中访问类A的所有成员(成员变量、成员函数),而不管这些成员在类A中是用什么修饰符(private、protected、public)修饰的。如果现在类A和类B都变成了类模板,那么能否让类模板B成为类模板A的友元类模板呢?这要分3种情况讨论。

1.让类模板的某个实例成为友元类

template<typename T>
classA {
private:
    int data;
};

template<typename U>
classB {
public:
    void callBAF(){
        A<int> atmpobj;
        atmpobj.data = 5;
        std::cout << atmpobj.data << std::endl;
    }
};

在main()主函数中添加代码:

B<long>bobj;
bobj.callBAF();

上面这段代码编译后会报错,因为类模板B的callBAF()成员函数要访问类模板A的私有成员变量data,这是不允许的。那么,如果类模板B成为类模板A的朋友,显然就会解决编译出错的问题。于是,调整类模板A的代码,增加一个friend声明,调整后的类模板A的代码如下。

template<typename T>
classA{
    friend classB<long>;//不需要任何public、private等修饰符修饰
private:
    intdata;
};

此外,还需要在类模板A定义的前面增加针对类模板B的声明(如果B不是类模板,而只是一个普通类,就不需要增加针对类B的声明)。

template<typename U> class B; // 类模板B声明

从上面的代码中可以看到,实际是让类模板B的特定类模板实例(也就是B<long>)成为类模板A的友元类。也就是说,B<long>实际上代表的是一个具体的类(如果B不是类模板,而是普通类,就不需要增加针对类B的声明)。

2.让类模板成为友元类模板

前面的代码只是让B<long>成为类模板A的友元类,如果调整main()主函数中的代码B<long>为B<int>,则再次运行会报错。因为B<int>并不是类模板A的友元类,如果把整个类模板B变成类模板A的友元类模板,这个问题就解决了,而且不需要再类模板A定义前增加针对类模板B的声明。

template<typename T>
class A{
    template<typename> friend class B;
public:
    int data;
};

现在,类模板B成立类模板A的友元类模板。

2. 友元函数

函数模板可以被声明为友元函数,首先定义一个普通的函数模板。

template<typename U, typename V>
void func(U val1, V val2) {
    cout << "val1=" << val1 << endl;
    cout << "val2=" << val2 << endl;
}

当要调用func()函数时:

func(2, 3);
func<float>(4.6f, 5)
func<int, float>(4, .8f)

现在,在func()函数模板的前面增加一个Men类的定义:

class Men {
private:
    void funcmen() const {
        cout << "Men::funcmen被调用了" << endl;
    }
};

修改func()函数模板中的代码:

template<typename U, typename V>
void func(U val1, V val2) {
    Men mymen;
    mymen.funcmen(); // func()不是Men类的友元函数,不能访问Men类的私有成员函数
}

1. 让函数模板的某个实例成为友元函数

在main()函数中,func(2, 3)会实例化出void func<int, int>(int, int) {...}。所以把实例化后的func<int, int>函数声明为Men类的友元,在Men类中添加代码:

friend func<int, int>(int, int);

尖括号中的内容叫做模板实参,两个模板实参可以从func()的圆括号指定的实参推导出来,因此尖括号中的内容可以省略,也可以保留一个,但是尖括号不能省略。

同时,在Men类定义的上面添加函数模板func()的声明:

template<typename U, typename V> void func(Uval1, val2);

2. 友元模板

上面的实例中,只是将函数模板func()的某个实例成为Men类模板的友元函数。为了应对不同的情况,可以让函数模板成为Men类模板的友元模板。

方法是在Men类模板的定义中添加代码行:

template<typename U, typename V> friend void fun(U val1, V val2);

如此则不需要在类模板Men定义的前面增加针对函数模板的声明。

3. 在类模板中定义友元函数

可以在一个类模板中定义(不是声明)一个友元函数,这种友元函数是能够被调用的,而且只有在被调用时,编译器才会实例化这个函数。虽然下面的函数func2()的定义写在了Men类模板中,但是应该把它看作一个全局函数,不接受Men类模板的限制。

template<typename z>
class Men {
    friend void func2(Men<z> &tmpmen) {
        tmpmen.funcmen();
    }
    ...
};

在main()函数中添加代码:

Men<double> mymen2;
func2(mymen2);
Men<int> mymen3;
func2(mymen3)

值得一提的是,如果func2()的代码非常简单,编译器会将func2()当作内联函数来处理。

可以看到,虽然func2()是写在了Men类模板的定义中(好处是可以访问类模板中的私有成员),但它的作用域是全局作用域,所以func2()是一个全局函数。

标签:友元,函数,Men,模板,func,友元类
From: https://www.cnblogs.com/love-9/p/18104511

相关文章

  • C++精品小案例:C++中的多态性及其实现、模板元编程及其在C++中的应用
    1.C++中的多态性及其实现多态性是面向对象编程的三大特性之一,它允许使用父类类型的指针或引用来指向子类对象,并通过这个父类类型的指针或引用来调用实际子类的成员函数。这样,就可以在运行时确定应该调用哪个具体的函数实现,从而实现一个接口多种形态。多态性主要通过虚函数来......
  • WPF中使用PDF模板实现PDF导出和预览-来自GPT4
    在C#和WPF项目中实现加载不同的PDF模板、查看报告和导出PDF文件的功能,可以通过以下步骤完成:1.选择PDF库首先,选择一个合适的.NETPDF库。有许多库可以帮助你处理PDF文件,包括但不限于:iTextSharp:一个功能强大的和灵活的库,适用于创建和修改PDF文件。它是iText的一个.NET端口。......
  • 【Vue】模板语法
    用js完成输出输入框中的值到列表中constbuttonEl=document.querySelector('button');constinputEl=document.querySelector('input');constlistEl=document.querySelector('ul')0;functionaddGoal(){ constenteredValue=inputEl.value; c......
  • 【模板】快速读入
    1inlineintread()2{3intw=0,s=1;4charch=getchar();5while(ch<'0'||ch>'9')6{7if(ch=='-')s=-1;8ch=getchar();9}10while(ch>='0'&&ch<='9')11{12w=w*10+ch......
  • 软件项目管理全套文档模板(开发/实施/运维/安全/交付)
     前言:在软件项目管理中,每个阶段都有其特定的目标和活动,确保项目的顺利进行和最终的成功交付。以下是软件项目管理各个阶段的详细资料:软件项目全套文档资料下载:点我获取1.需求阶段目标:收集、分析和定义用户需求和业务目标。主要活动:需求调研:与用户沟通,了解他们的需求和......
  • FLASK学习记录-宏、模板继承
    宏{%macroname%}{%endmacro%}app.pyfromflaskimportFlask,render_templateapp=Flask(__name__)@app.route('/')defindex1():returnrender_template("macro1.html")@app.route("/")defindex2():returnrend......
  • 软件项目管理全套通用模板(规格说明书~详细设计~测试计划~验收报告)
     前言:在软件开发过程中,文档资料是非常关键的一部分,它们帮助团队成员理解项目需求、设计、实施、测试、验收等各个环节,确保项目的顺利进行。以下是针对您提到的各个阶段的文档资料概述:所有资料获取:点击获取开发阶段需求规格说明书:详细描述了软件系统的功能需求、非功能......
  • 写模板,线段树
    1意义:线段是是为了对区间中的元素进行操作,而衍生出来的一种数据结构,比如区间加减,区间求和。线段树将1~n的区间分解成4n个小区间。2过程:区间修改就是对一个或者多个节点按照设定的规则对数值进行修改。区间查询就是对一个或多个节点查询的结果按规则进行合并,得到最终结果。其......
  • 最近公共祖先(lca)倍增算法【模板】
    P3379【模板】最近公共祖先(LCA)-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>#include<cstdio>usingnamespacestd;constintN=5e5+100;constintinf=0x3f3f3f;intn,m,s;vector<int>g[N];intdep[N];//存u点的深度intfa[N][20];//存从u......
  • Floyd算法 【多源最短路】模板
    B3647【模板】Floyd-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>usingnamespacestd;constintN=1e2+10;constintinf=0x3f3f3f;intn,m;intg[N][N];voidfloyd(){for(intk=1;k<=n;k++){for(inti=1;i<=n;i++)......