我正在读这样的代码:
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
在类体内定义非成员函数是一个好习惯吗?有什么优点和缺点?
答案 0 :(得分:5)
使用好友在类体内定义非成员函数是一个好习惯吗?
无所谓的做法,我会说。
有什么优点和缺点?
运算符可以在类的范围内引用类成员(嵌套类,typedef,枚举,常量,静态函数等),而无需使用类名明确地为它们添加前缀
隐式地使用流功能inline
- 没有一个定义规则麻烦
友谊意味着您可以方便地访问所有非公开成员
研究课程源代码的人更有可能注意到流媒体功能
正如Mike Seymour评论的那样,如果该类是模板,那么定义一个朋友可以省略运算符的template <
... >
方面,并简单地引用实例参数作为const Member&
而不是const Member<
... >&
。
您可能想要一个外联函数定义,这样您以后可以修改实现,只需要重新链接(而不是重新编译)客户端代码
你正在给予可能没有功能上必要的友谊,这会减少封装,从而减少可维护性
寻找非会员流媒体运营商的人可能不会考虑查看课程代码
你可能认为它“混乱”了类定义源代码,使得更难以接受实际类成员的整体
与往常一样,界面和实现的清晰分离 - 管理物理依赖性(需要重新编译而不仅仅是重新链接)和人类可读性的好处 - 对于不同的高级库使用的低级库而言往往会增加应用程序,并且远低于本地实现的“私有”支持(例如.cpp
文件中的匿名命名空间中的类,仅由该单个翻译单元使用,或者 - 更是如此 - {{1}嵌套类)。
答案 1 :(得分:4)
一般来说,不是良好做法;理想情况下, 实现甚至不会与类在同一个文件中 定义。 (理想情况下,我们也不必宣布 头文件中的私有部分。)有很多 然而,合理的例外情况是:
最明显的是真正简单的帮助类,其中 真的不足以证明分离这两个部分是合理的。 如果在本地定义辅助类,则尤其如此, 在源文件中,而不是在标题中。
另一种情况是朋友,尤其是模板。如果
我写(即使在模板中)friend void f( MyClass& )
,然后
我宣布一个非模板是朋友,我必须这样做
为每个实现单独的非模板功能
实例化类型。如果我在中提供内联实现
但是,类定义会自动生成
为每种类型创建单独的非模板函数
用过的。这是定义的非常频繁的动机
班级中operator>>
和operator<<
,因为他们不能
成员;通常他们将被宣布为friend
即使他们
不需要访问私人会员,只是为了他们可以
这样定义。
最后,如果没有其他功能声明或 运算符,它们只能在类中或ADL中可见。 这应该不是问题,只要函数有 至少一个涉及该类的参数。
答案 2 :(得分:1)
可能的专业: 如果您拥有处理类主体内定义的类私有成员的所有或大多数其他函数,则更易于阅读和维护。它将事物保持在一起。
缺点: 类主体中定义的函数出现在每个编译单元中,而不是只编译一个可以放入它们的相应.cpp文件。