C++类内定义友元却无需类外声明的特殊情况

C++类内定义友元却无需类外声明的特殊情况

将一个全局函数作为某个类的友元时,可以在类内定义函数,但必须在类外对函数进行声明。但有一种特殊情况并不需要再次声明。例如:

#include <iostream>

class Person
{
public:
    friend void func1()
    {
        std::cout << "func1" << std::endl;
    }
    friend void func2(const Person& p)
    {
        std::cout << "func2" << std::endl;
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& p)
    {
        os << p.age;
        return os;
    }
    friend Person& operator+(Person& p, int a)
    {
        p.age += a;
        return p;
    }
    
private:
    int age = 0;
};

int main()
{
    Person p;
    // func1();  Error
    func2(p);
    std::cout << p << std::endl;
    std::cout << (p + 8) << std::endl;
}

在上述例子中,四个函数都没有在类外进行声明,但只有func1调用会出错,其他函数调用正常。不难发现,只有func1函数的形参列表中不包含Person类。也就是说:
当友元函数定义在类内时,如果函数使用了该类作为参数,则不需要在类外声明

原因也许和模板有关,例如有如下类模板:

#include <iostream>
#include <vector>

template <typename T>
class Stack
{
public:
    void push(T value)
    {
        elems.push_back(value);
    }
    friend std::ostream& operator<<(std::ostream& os, const Stack<T>& s)
    {
        s.print();
        return os;
    }
    
private:
    void print() const
    {
        for (const T& item : elems)
        {
            std::cout << item << " ";
        }
    }
    std::vector<T> elems;
};

int main()
{
    Stack<int> s;
    for (int i = 3; i < 9; ++i)
    {
        s.push(i);
    }
    std::cout << s << std::endl;
}

Stack类模板里重载了<<运算符,并作为友元,上述代码表示:Stack每次实例化的时候,会同时实例化一个operator<<函数,注意,operator<<函数并不是函数模板。因此如果想在类外进行声明时,需要对不同Stack的实例写不同的声明,例如:

// 如果实例化了Stack<int>
std::ostream& operator<<(std::ostream& os, const Stack<int>& s);
// 如果实例化了Stack<double>
std::ostream& operator<<(std::ostream& os, const Stack<double>& s);
...

这样的代码并不generic,原因就是类模板作为参数可以有很多不同的类型,因此,如果友元函数使用了该类作为参数,则不需要在类外声明。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值