C++ TGP 模板基础知识--03 类模板中的友元

友元类

让某个类B成为另一个类A的友元类,这样的话类B就可以在其成员函数中访问A的所有成员,而不管这些成员在类A在中是用什么(public,protected, private)修饰符修饰的。

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

#include 

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

template <typename T>
class A {
    friend class B<long>;  // 类模板B的实例B 成为A的友元类
  private:
    int data;
};

template <typename D>
class B {
  public:
    void callBAF()
    {
        A<int> a_obj;
        a_obj.data = 5;
        std::cout << a_obj.data << std::endl;
    }
};

int main(int argc, char** argv)
{
    B<long> b_obj;
    b_obj.callBAF();
    return 0;
}

让类模板成为友元类模板

#include 

template <typename T>
class A {
    template <typename D>
    friend class B; // 类模板B成为A的友元类
  private:
    int data;
};

template <typename D>
class B {
  public:
    void callBAF()
    {
        A<int> a_obj;
        a_obj.data = 5;
        std::cout << a_obj.data << std::endl;
    }
};

int main(int argc, char** argv)
{
    B<int> b_obj;
    b_obj.callBAF();
    return 0;
}

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

如果传递进来的类型模板参数是一个类类型,则这个类类型可以成为当前类模板的友元类.如果传递给类型模板参数不是一个类类型,那么就被忽略

#include 

template <typename T>
class A {
    friend T; // 如果传入不是类类型,这行代码将会被忽略

  private:
    int data;
};

class B {
  public:
    void callA()
    {
        A<B> a_obj;  // 让B成为A类的友元类
        a_obj.data = 12;
        std::cout << a_obj.data << std::endl;
    }
};

int main(int argc, char** argv)
{
    B b_obj;
    b_obj.callA();

    // A a_obj;  因为B类并不是A的友元类,因此不能访问私有成员变  量
    // a_obj.data = 12;
    return 0;
}

友元函数

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

#include 

// 函数模板func的声明
template <typename U, typename V>
void func(U val1, V val2);

template<typename T>
class Men {
    friend void func<int, int>(int, int);  // 是两个模板实参
    friend void func<float, int>(float, int);
    friend void func<int, float>(int, float);

  private:
    void func_man() const
    {
        std::cout << "Men::func_man called" << std::endl;
    }
};

template <typename U, typename V>
void func(U val1, V val2)
{
    std::cout << "val1:" << val1 << " val2:" << val2 << std::endl;
    Men<int> men;
    men.func_man();
}

int main(int argc, char** argv)
{
    // 函数模板调用方式
    func(2, 3);  // 实例化void func(int, int){...}
    func<float>(4.6f, 5);  // 第一个模板参数指定,第二个模板参数编译器推断
    func<int, float>(4, 5.6f);
    return 0;
}

友元模板

将函数模板(泛化版本)声明为类模板的友元模板之后,那么函数模板的特化版本也会成为类模板的友元

#include 

template <typename T>
class Men {
    // 函数模板成为类模板的友元函数模板
    template <typename U, typename V>
    friend void func(U, V);

  private:
    void func_man() const
    {
        std::cout << "Men::func_man called" << std::endl;
    }
};

// func 泛化版本
template <typename U, typename V>
void func(U val1, V val2)
{
    std::cout << "泛化版本:"
              << "val1:" << val1 << " val2:" << val2 << std::endl;
    Men<int> men;
    men.func_man();
}

// func 全特化版本
template <>
void func(double val1, double val2)
{
    std::cout << "全特化版本:"
              << "val1:" << val1 << " val2:" << val2 << std::endl;
    Men<int> men;
    men.func_man();
}

int main(int argc, char** argv)
{
    // func(2, 3);
    // func(4.6f, 5);
    // func(4, 5.6f);
    // func(4.8, 5.6);
    return 0;
}

在类模板中定义友元函数

这种友元函数能够被调用,而且只有在代码中调用了函数的时候,编译器才会实例化出这个函数,之所以这样定义友元函数,一般是因为在该友元函数中会用到这个类模板。这种友元函数的调用与普通函数一样。

#include 

template <typename T>
class Men {
    friend void func(Men<T>& men)
    {
        men.func_man();
    };

  private:
    void func_man() const
    {
        std::cout << "Men::func_man called" << std::endl;
    }
};

int main(int argc, char** argv)
{
    Men<double> man; // 虽然func在Men类模板中,还未调用,因此func还未实例化
    func(man); // 直接调用Men类模板中定义的友元函数func
    return 0;
}

你可能感兴趣的:(C/C++,c++,开发语言)