美文网首页
类模板中的友元

类模板中的友元

作者: 404Not_Found | 来源:发表于2021-12-31 21:49 被阅读0次
  • 作者: 雪山肥鱼
  • 时间:20220101 13:39
  • 目的: 类模板中的友元

友元的定义

让类B 成为 类A 的友元。那么类B 可以在自己的成员函数中访问类A的所有成员,而不管这些成员是否用了public private protected 进行修饰。
这里需要注意
类B 成为 类A 的友元,即类B 主动和 类A 成为朋友,是类B 可以访问类A的私有成员,反之则错误。
我们来讨论 类A 和 类B 都成为类模板的情况。

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

即B<long>, 实例化,让B 成为 long 的类型

template <typename U> class B;//前向声明

template<typename T>
class A {
    friend class B<long>;//不需要任何的 public private protected 访问修饰符
private:
    int data;
};

template<typename U>
class B {
public:
    void callAFunc() {
        A<int> aObj;
        aObj.data = 5;
        cout << aObj.data << endl;
    }
};

int main() {
    B<long> bObj;
    bObj.callAFunc();
};
  1. 这里是需要对B 进行前向声明。
  2. friend class B<long> 不需要任何的访问限制符进行修饰
  3. 从 B<long> 改成 B<int> 立刻失效。因为只有 class B<long> 这个实例化了的类,才是 类模板 A 的友元。

全类型 友元

//template <typename U> class B; 可去掉声明, B成为A 的朋友,B 可以访问A
template<typename T>
class A {
    //friend class B<long>;
    template<typename> friend  class B;
private:
    int data;
};

template<typename U>
class B {
public:
    void callAFunc() {
        A<int> aObj;
        aObj.data = 5;
        cout << aObj.data << endl;
    }
};

int main() {
    B<int> bObj;
    bObj.callAFunc();
};
  1. 对friend 进行修改。
  2. 可以省略 模板B 的前向声明

让类型模板参数成为友元类

如果类型模板 用一个自己创建的类类型进行实例化,如何让这个类成为当前类模板的友元类
用文字难以形容,代码实际一些:

template<typename T>
class A {
    //让传进来的CF 成为类模板 A 的 友元类(如果传进来的是CF,则实例化成CF类)
    friend T;
private:
    int data;
};


class CF {
public:
    void callAFunc() {
        A<CF> aobj1;
        aobj1.data = 12; //对 类模板的私有成员进行了访问
        cout << aobj1.data << endl;
    }
};

int main() {
    CF cf;
    cf.callAFunc();

    /*
    //这肯定不行的。
        A<CF> aobj1;    
        aobj1.data = 12;
    */


    return 0;
}

但是,依旧存在问题,如果这时候传进来的 是 一个
普通类型,如int,则这个友元就会失效, 即忽略 friend

class CF {
public:
    void callAFunc() {
        A<CF> aobj1;
        aobj1.data = 12;
        cout << aobj1.data << endl;

        //当然如果传进来的 非 一个 类类型,则会被忽略。
        A<int> aobj2;
        aobj2.data = 12;//因为CF类并不是A<int> 的友元类,所以不能访问aobj2这个 A<int> 类的私有成员变量
    }
};

解决方案:增加一行代码即可

template<typename T>
class A {
    friend T;
    friend class CF;//不管A 被 具体实例化成 哪个类(int也好,其他类也号),CF类都是 class A 的友元
private:
    int data;
};


class CF {
public:
    void callAFunc() {
        A<CF> aobj1;
        aobj1.data = 12;
        cout << aobj1.data << endl;

        //当然如果传进来的 非 一个 类类型,则会被忽略。
        A<int> aobj2;
        aobj2.data = 12;//因为CF类并不是A<int> 的友元类,所以不能访问aobj2这个 A<int> 类的私有成员变量
    }
};

int main() {
    CF cf;
    cf.callAFunc();

    /*
    //这肯定不行的。
        A<CF> aobj1;
        aobj1.data = 12;
    */
    return 0;
}

友元函数

函数模板可以被声明为友元函数
传统模板函数回顾

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

int main() {
    //调用func 方法很多
    func(2, 3);//编译器自己推断
    func<float>(4.6f, 5);//第一个指定,第二个编译器自己推出
    func<int, int>(1, 2);// 完全手工指定模板参数
    return 0;
}

针对特定类型的 友元函

//只是针对某一特定类型
//增加声明
template<typename T, typename V> void func(T, V);

class Men {
    //friend void func<int, int>(int, int);//实际上是已经被实例化模板实参了。
        //friend void func<>(int, int);//可以推断出来的,没有问题
    //friend void func<int>(int, int);//可以
private:
    void funcmen() const
    {
        cout << "Men::funcmen() is called" << endl; 
    }
};

template<typename U, typename V>
void func(U val1, V val2) {
    Men mymen;
    mymen.funcmen();
}

int main() {
    //func(2,3); 会实例化出 void func<int,int>(int, int) {...},所以可以在men类中操作
    func(2, 3);
    return 0;
}

当然把Men 改成 模板 也是可以的

友元模板

//template<typename T, typename V> void func(T, V);

template<typename T>
class Men {
    template<typename U, typename T> friend void func(U val1, T val2);
private:
    void funcmen() const
    {
        cout << "Men::funcmen() is called" << endl;
    }
};

template<typename U, typename V>
void func(U val1, V val2) {
    Men<int> mymen;
    mymen.funcmen();
}

int main() {
    //func(2,3); 会实例化出 void func<int,int>(int, int) {...},所以可以在men类中操作
    func(2, 3);
    func<int, double>(2.0, 3.1);
    return 0;

可以舍去前向声明。
泛化版本声明为Men类模板的友元函数之后,那么func函数的特化版本也会被看成Men类模板的友元。


template<typename T>
class Men {
    template<typename U, typename T> friend void func(U val1, T val2);
private:
    void funcmen() const
    {
        cout << "Men::funcmen() is called" << endl;
    }
};

template<typename U, typename V>
void func(U val1, V val2) {
    Men<int> mymen;
    mymen.funcmen();
}

template<>
void func<int, int>(int val1, int val2) {
    cout << "func<>() 全特化被调用" << endl;
    Men<int> mymen;
    mymen.funcmen();
}

int main() {
    func(2, 3);
    func<int, double>(2.0, 3.1);
    return 0;
}

另注:
编译器会把全特化的func函数模板看待成一个实例化过的函数模板。

在类模板中定义友元函数

//在类模板中定义友元函数
//是定义 非声明,且只有在代码中调用了函数的时候,编译器才会实例化出这个函数
//一般都是因为在该友元函数中 会用到类模板, 当成全局函数看待就行了

template<typename Z>
class Men {
    friend void funz(Men<Z> & temp) {
        temp.funcmen();
    }
private:
    void funcmen() const
    {
        cout << "Men::funcmen() is called" << endl;
    }
};

int main() {
    Men<double> mymen2;
    funz(mymen2);//类似全局函数,直接调用就行了,只有调用的时候,才会被实例化出来
    return 0;
}
  1. 类似全局函数
  2. 只有当被调用,才会被实例化
  3. 因为funz在类模板中且函数体比较简单,会被当成内联函数使用

相关文章

  • 14/15

    约束模板友元 模板类的外边定义一个模板函数,在模板类中将模板函数具体化为模板类的友元函数 非约束模板友元 模板类中...

  • 类模板中的友元函数

    今天写cpp的时候,忘记了类模板中的友元怎么用了记录一下 先声明类模板,和友元函数 类模板中声明友元函数 类模板外...

  • 14/14模板和友元之非模板友元

    1.非模板友元:将模板类中的函数作为友元

  • 10-C++远征之模板篇-学习笔记

    C++远征之模板篇 将会学到的内容: 模板函数 & 模板类 -> 标准模板类 友元函数 & 友元类 静态数据成员 ...

  • 慕课网-C++远征之模板篇(上)-学习笔记

    C++远征之模板篇 将会学到的内容: 模板函数 & 模板类 -> 标准模板类 友元函数 & 友元类 静态数据成员 ...

  • C++类模板与友元的关系

    总结起来一共有这么几条: 如果一个类模板包含一个非模板友元,则友元被授权可以访问所有类模板实例。 如果一个非模板类...

  • C++模板

    要点 模板函数在类的外部定义 友元函数在类的外部定义(<<的重载) 模板类中静态变量的使用规则 示例 Array....

  • 15.C++泛型

    模板函数 模板类 函数模板和友元函数 注意,只在重载左移右移运算符的时候使用友元函数,其他都不要用,友元函数容易导...

  • C++11笔记

    友元类是模板类的声明 有一个类成员私有,希望指定的模板类可以访问,比如: 只希望Container能访问私有成员,...

  • c++ 友元

    在c++中,通过关键字friend声明为友元。友元可以范围与其有好友关系的类中私有成员。友元包括友元函数和友元类。...

网友评论

      本文标题:类模板中的友元

      本文链接:https://www.haomeiwen.com/subject/ypboqrtx.html