没有友元函数,哪些 C++ 运算符根本不能重载?
7 回答
只有在以下情况下,您才需要朋友声明:
- 您将运算符定义为类外部的独立函数,并且
- 实现需要使用私有函数或变量。
否则,您可以在没有友元声明的情况下实现任何运算符。为了使它更具体一点......可以在类*内部和外部定义各种运算符:
// Implementing operator+ inside a class:
class T {
public:
// ...
T operator+(const T& other) const { return add(other); }
// ...
};
// Implementing operator+ outside a class:
class T {
// ...
};
T operator+(const T& a, const T& b) { return a.add(b); }
如果在上面的示例中,“add”函数是私有的,那么在后一个示例中需要有一个朋友声明operator+
才能使用它。但是,如果“add”是公开的,则在该示例中无需使用“friend”。Friend 仅在需要授予访问权限时使用。
*在某些情况下,无法在类中定义运算符(例如,如果您无法控制该类的代码,但仍想提供该类型在左侧的定义,无论如何) . 在这些情况下,关于友元声明的相同声明仍然适用:友元声明仅用于访问目的。只要操作符函数的实现只依赖于公共函数和变量,就不需要友元声明。
左侧操作数不是类本身的运算符。例如cout << somtething
,可以通过定义一个std::ostream& operator<<(std::ostream& lhs, Something const & rhs);
函数并将它们标记为friend
类内部来实现。
编辑:永远不需要交友。但它可以让事情变得更简单。
使用友元函数的唯一原因是访问私有(包括受保护)成员变量和函数。
你永远不需要朋友功能。如果您不希望运算符成为成员(通常是不修改其操作数的二元运算符的情况),则不需要它成为朋友。但是,有两个原因可以使它成为朋友:
- 为了访问私有数据成员,以及
- 为了在类主体中定义它(即使它不是成员),以便 ADL 找到它
第二个原因主要适用于模板,但是在模板基类中定义+
和这样的操作符是很常见的,就
and而言,所以这是最常见的情况。-
+=
-=
运算符重载和友谊是正交的概念。您需要在需要访问该类型的私有成员时声明一个函数(任何函数)friend
,因此如果您将运算符重载为不是成员的函数并且该实现需要访问私有成员,那么它应该是朋友。
请注意,通常最好不要声明friend
s,因为这是该语言中最高的耦合关系,因此您应该尽可能根据您的类型的公共接口实现运算符的自由函数重载(允许您更改类型的实现而不必重写运算符)。在某些情况下,建议将operatorX
作为一个自由函数operatorX=
实现为一个公共成员函数(更多关于运算符重载here)
有一个特定的极端情况,使用类模板,您可能希望将自由函数运算符声明为模板的朋友,以便能够在模板类中定义它,即使它不需要访问私有成员:
template <typename T>
class X {
int m_data;
public:
int get_value() const { return m_data; }
friend std::ostream& operator<<( std::ostream& o, X const & x ) {
return o << x.get_value();
}
};
这样做的好处是您可以以简单直接的方式将单个非模板化函数定义为友元。要将定义移到类模板之外,您必须将其设为模板,并且语法变得更加繁琐。
this
当不是左侧时,或者this
需要隐式转换的位置时,您需要使用友元函数。
编辑:当然,如果您确实需要该friend
部分以及免费功能部分。
运算符[] -> =
必须是成员函数。
其他可接受的重载二元运算符可以写成函数形式或成员函数形式。可接受的重载运算符是所有一元和二元 C++ 运算符,除了
: . :: typeid 的大小?