把非成员函数放在类中是一种好的做法吗

Is it a good practise to put non member function inside a class?

本文关键字:一种 函数 成员      更新时间:2023-10-16

我正在读这样的代码:

class Member
{
public:
    friend std::istream& operator>>(std::istream& in, Member& m)
    {
        in >> m.name >> m.bYear >> m.bMonth;
        return in;
    }
    friend std::ostream& operator<<(std::ostream& out,const Member& m)
    {
        out << m.name << " " << m.bYear << "." << m.bMonth;
        return out;
    }
private:
    std::string name;
    int year;
    int month;
};

我以前从未见过这种情况。用friend在类主体内定义非成员函数是一种好的做法吗?有什么优点和缺点吗?

和friend一起在类主体中定义非成员函数是一种好的做法吗?

我想说,这是一种冷漠的做法。

有什么优点和缺点吗?

优点

  • 运算符可以引用类作用域中的类成员(嵌套类、typedef、枚举、常量、静态函数等),而无需显式地在它们前面加上类名

  • 隐式地拥有流式传输函数inline是很方便的——没有一个定义规则会困扰

  • 友谊意味着您可以方便地访问所有非公开会员

  • 研究类源代码的人更有可能注意到的流功能

  • 正如Mike Seymour所评论的,如果类是一个模板,那么定义一个朋友可以省略template <。。。运算符的>方面,并将实例参数简单地称为const Member&而不是const Member<。。。>&

Cons

  • 您可能想要一个越界的函数定义,这样您以后就可以修改实现,只需要重新链接(而不是重新编译)客户端代码

  • 你给予的友谊可能在功能上是不必要的,这减少了封装,从而减少了的可维护性

  • 寻找非会员流媒体运营商的人可能不会考虑查看类代码

  • 你可能会认为它"扰乱"了类定义源代码,使其更难接受的所有实际类成员

与往常一样,接口和实现的干净分离的好处——既有利于管理物理依赖性(需要重新编译而不仅仅是重新链接),也有利于人类可读性——对于不同的高级库和应用程序使用的低级库来说,这一好处往往会增加,并且对于本地实现的"私有"支持要低得多(例如,.cpp文件中匿名命名空间中的类,仅由该单个翻译单元使用,或者更确切地说,是private嵌套类)。

一般来说,这不是的好做法;理想情况下实现甚至不会与类在同一个文件中释义(理想情况下,我们也不必声明头文件中的私有部分。)有很多但有正当理由的例外情况:

  • 最明显的是在非常简单的助手类中真的没有足够的理由将两部分分开。如果辅助类是本地定义的,在源文件中,而不是在标头中。

  • 另一种情况是针对朋友,尤其是在模板中。如果我写(甚至在模板中)friend void f( MyClass& ),然后我已经声明了一个非模板作为朋友,我必须为每个实现一个单独的非模板函数实例化类型。如果我在中提供内联实现然而,类定义,编译器将自动为每种类型创建单独的非模板函数习惯于这是一个非常频繁的定义动机类中的operator>>operator<<,因为它们不能成员;通常它们将被声明为friend,即使它们不需要访问私人成员,这样他们就可以这样定义。

最后,如果函数或运算符,它们仅在类中或ADL中可见。这应该不是问题,只要函数在至少一个涉及类的参数。

可能的Pro:如果在类主体中也定义了所有或大多数其他函数来处理类的私有成员,则更易于阅读和维护。它使事物保持在一起。

Con:类主体中定义的函数出现在每个编译单元中,而不是只编译一个相应的.cpp文件。

相关文章: