C++ 友元函数重载运算符 <<

1. Friend functions (友元函数)

As you’ve seen, C++ controls access to the private portions of a class object. Usually, public class methods serve as the only access, but sometimes this restriction is too rigid to fit particular programming problems. In such cases, C++ provides another form of access: the friend.
C++ 控制对类对象私有部分的访问。通常,公有类方法提供唯一的访问途径,但是有时候这种限制太严格,以致于不适合特定的编程问题。在这种情况下,C++ 提供了另外一种形式的访问权限:友元。

Friends come in three varieties:

  • Friend functions (友元函数)
  • Friend classes (友元类)
  • Friend member functions (友元成员函数)

By making a function a friend to a class, you allow the function the same access privileges that a member function of the class has.
通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。

In the previous Time class example, the overloaded multiplication operator is different from the other two overloaded operators in that it combines two different types. That is, the addition and subtraction operators each combine two Time values, but the multiplication operator combines a Time value with a double value. This restricts how the operator can be used. Remember, the left operand is the invoking object.
Time 类示例中,重载的乘法运算符与其他两种重载运算符的差别在于,它使用了两种不同的类型。加法和减法运算符都结合两个 Time 值,而乘法运算符将一个 Time 值与一个 double 值结合在一起。这限制了该运算符的使用方式。记住,左侧的操作数是调用对象。

That is,

A = B * 2.75;

translates to the following member function call:

A = B.operator*(2.75);

But what about the following statement?

A = 2.75 * B;  // cannot correspond to a member function

Conceptually, 2.75 * B should be the same as B * 2.75, but the first expression cannot correspond to a member function because 2.75 is not a type Time object. Remember, the left operand is the invoking object, but 2.75 is not an object. So the compiler cannot replace the expression with a member function call.
从概念上说,2.75 * B 应与 B * 2.75 相同,但第一个表达式不对应于成员函数,因为 2.75 不是 Time 类型的对象。记住,左侧的操作数应是调用对象,但 2.75 不是对象。因此,编译器不能使用成员函数调用来替换该表达式。

One way around this difficulty is to tell everyone (and to remember yourself) that you can only write B * 2.75 but never write 2.75 * B. This is a server-friendly, client-beware solution, and that’s not what OOP is about.
解决这个难题的一种方式是,告知每个人 (包括程序员自己),只能按 B * 2.75 这种格式编写,不能写成 2.75 * B。这是一种对服务器友好 - 客户警惕的解决方案,与 OOP 无关。

However, there is another possibility - using a nonmember function. Remember, most operators can be overloaded using either member or nonmember functions. A nonmember function is not invoked by an object; instead, any values it uses, including objects, are explicit arguments.
还有另一种解决方式使用非成员函数,大多数运算符都可以通过成员或非成员函数来重载。非成员函数不是由对象调用的,它使用的所有值 (包括对象) 都是显式参数。

Thus, the compiler could match the expression

A = 2.75 * B;  // cannot correspond to a member function

to the following nonmember function call:

A = operator*(2.75, B);

The function would have this prototype:

Time operator*(const double factor, const Time & time);

With the nonmember overloaded operator function, the left operand of an operator expression corresponds to the first argument of the operator function, and the right operand corresponds to the second argument.
对于非成员重载运算符函数来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。

Using a nonmember function solves the problem of getting the operands in the desired order (first double and then Time), but it raises a new problem: Nonmember functions can’t directly access private data in a class. Well, at least ordinary nonmember functions lack access. But there is a special category of nonmember functions, called friends, that can access private members of a class.
使用非成员函数可以按所需的顺序获得操作数 (先是 double,然后是 Time),但引发了一个新问题:非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问。然而,有一类特殊的非成员函数可以访问类的私有成员,它们被称为友元函数。

1.1. Creating Friends (创建友元)

The first step toward creating a friend function is to place a prototype in the class declaration and prefix the declaration with the keyword friend.
创建友元函数的第一步是将其原型放在类声明中,并在原型声明前加上关键字 friend

friend Time operator*(const double factor, const Time & time);

This prototype has two implications:

  • Although the operator*() function is declared in the class declaration, it is not a member function. So it isn’t invoked by using the membership operator.
    虽然 operator*() 函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用。
  • Although the operator*() function is not a member function, it has the same access rights as a member function.
    虽然 operator*() 函数不是成员函数,但它与成员函数的访问权限相同。

Because it is not a member function, you don’t use the Time:: qualifier. Also you don’t use the friend keyword in the definition.
因为它不是成员函数,所以不要使用 Time:: 限定符。不要在定义中使用关键字 friend

The definition should look like this:

Time operator*(const double factor, const Time & time) {
	Time result;
	const long total_minutes = time.hours * factor * 60 + time.minutes * factor;
	result.hours = total_minutes / 60;
	result.minutes = total_minutes % 60;
	return result;
}

With this declaration and definition, the statement

A = 2.75 * B;

translates to the following and invokes the nonmember friend function just defined:

A = operator*(2.75, B);

In short, a friend function to a class is a nonmember function that has the same access rights as a member function.
总之,类的友元函数是非成员函数,其访问权限与成员函数相同。

At first glance, it might seem that friends violate the OOP principle of data hiding because the friend mechanism allows nonmember functions to access private data. However, that’s an overly narrow view. Instead, you should think of friend functions as part of an extended interface for a class.
乍一看,您可能会认为友元违反了 OOP 数据隐藏的原则,因为友元机制允许非成员函数访问私有数据。然而,这个观点太片面了。相反,应将友元函数看作类的扩展接口的组成部分。

By using both a friend function and a class method, you can express either operation with the same user interface. Also keep in mind that only a class declaration can decide which functions are friends, so the class declaration still controls which functions access private data. In short, class methods and friends are simply two different mechanisms for expressing a class interface.
通过使用友元函数和类方法,可以用同一个用户接口表达这两种操作。另外请记住,只有类声明可以决定哪一个函数是友元,因此类声明仍然控制了哪些函数可以访问私有数据。总之,类方法和友元只是表达类接口的两种不同机制。

Actually, you can write this particular friend function as a non-friend by altering the definition so that it switches which value comes first in the multiplication.
实际上,按下面的方式对定义进行修改,交换乘法操作数的顺序,可以将这个友元函数编写为非友元函数:

Time operator*(const double factor, const Time & time) {
	return time * factor;  // use time.operator*(factor)
}

The original version accessed time.minutes and time.hours explicitly, so it had to be a friend. This version only uses the Time object time as a whole, letting a member function handle the private values, so this version doesn’t have to be a friend. Nonetheless, there are reasons to make this version a friend, too. Most importantly, it ties the function in as part of the official class interface. Second, if you later find a need for the function to access private data directly, you only have to change the function definition and not the class prototype.
原来的版本显式地访问 time.minutes and time.hours,所以它必须是友元。这个版本将 Time 对象 time 作为一个整体使用,让成员函数来处理私有值,因此不必是友元。然而,将该版本作为友元也是一个好主意。最重要的是,它将该函数作为正式类接口的组成部分。其次,如果以后发现需要函数直接访问私有数据,则只要修改函数定义即可,而不必修改类原型。

If you want to overload an operator for a class and you want to use the operator with a nonclass term as the first operand, you can use a friend function to reverse the operand order.
如果要为类重载运算符,并将非类的项作为其第一个操作数,则可以用友元函数来反转操作数的顺序。

  • time.h
#ifndef TIME_H_
#define TIME_H_

class Time {
private:
	int hours;
	int minutes;

public:
	Time();
	Time(const int h, const int m = 0);
	~Time();

	void AddMinutes(const int m);
	void AddHours(const int h);
	void Reset(const int h = 0, const int m = 0);
	Time operator+(const Time & time) const;
	Time operator-(const Time & time) const;
	Time operator*(const double factor) const;

	friend Time operator*(const double factor, const Time & time) {
		return time * factor;  // use time.operator*(factor)
	}  // inline definition
	friend std::ostream & operator<<(std::ostream & os, const Time & time);

	void Show() const;
};

#endif

  • time.cpp

Note again that the methods use the Time:: qualifier, whereas the friend function does not.
方法使用了 Time:: 限定符,而友元函数不使用该限定符。

#include <iostream>

#include "time.h"

Time::Time() {
	std::cout << "Time::Time()" << std::endl;
	hours = minutes = 0;
}

Time::Time(const int h, const int m) {
	std::cout << "Time::Time(const int h, const int m): h=" << h << ", m=" << m << std::endl;
	hours = h;
	minutes = m;
}

Time::~Time() {
	std::cout << "Time::~Time(): hours=" << hours << ", minutes=" << minutes << std::endl;
}

void Time::AddMinutes(const int m) {
	minutes += m;
	hours += minutes / 60;
	minutes %= 60;
}

void Time::AddHours(const int h) {
	hours += h;
}

void Time::Reset(const int h, const int m) {
	hours = h;
	minutes = m;
}

Time Time::operator+(const Time & time) const {
	std::cout << "Time::operator+(const Time & time)" << std::endl;
	Time sum;
	sum.minutes = minutes + time.minutes;
	sum.hours = hours + time.hours + sum.minutes / 60;
	sum.minutes %= 60;
	return sum;
}

Time Time::operator-(const Time & time) const {
	std::cout << "Time::operator-(const Time & time)" << std::endl;
	Time diff;
	const int tot1 = time.minutes + 60 * time.hours;
	const int tot2 = minutes + 60 * hours;
	diff.minutes = (tot2 - tot1) % 60;
	diff.hours = (tot2 - tot1) / 60;
	return diff;
}

Time Time::operator*(const double factor) const {
	std::cout << "Time::operator*(const double factor)" << std::endl;
	Time result;
	const long total_minutes = hours * factor * 60 + minutes * factor;
	result.hours = total_minutes / 60;
	result.minutes = total_minutes % 60;
	return result;
}

std::ostream & operator<<(std::ostream & os, const Time & time) {
	os << time.hours << " hours, " << time.minutes << " minutes";
	return os;
}

void Time::Show() const {
	std::cout << hours << " hours, " << minutes << " minutes";
}

  • sample.cpp
#include <iostream>

#include "time.h"

int main() {
	{
		Time yong(3, 35);
		Time qiang(2, 48);
		Time temp;

		std::cout << "\nyong and qiang:\n";
		std::cout << yong << "; " << qiang << std::endl << std::endl;

		temp = yong + qiang;     // operator+()
		std::cout << "yong + qiang: " << temp << std::endl << std::endl;

		temp = yong * 1.17;  // member operator*()
		std::cout << "yong * 1.17: " << temp << std::endl << std::endl;

		std::cout << "10.0 * qiang: " << 10.0 * qiang << std::endl << std::endl;
	}

	return 0;
}

在这里插入图片描述

Time::Time(const int h, const int m): h=3, m=35
Time::Time(const int h, const int m): h=2, m=48
Time::Time()

yong and qiang:
3 hours, 35 minutes; 2 hours, 48 minutes

Time::operator+(const Time & time)
Time::Time()
Time::~Time(): hours=6, minutes=23
Time::~Time(): hours=6, minutes=23
yong + qiang: 6 hours, 23 minutes

Time::operator*(const double factor)
Time::Time()
Time::~Time(): hours=4, minutes=11
Time::~Time(): hours=4, minutes=11
yong * 1.17: 4 hours, 11 minutes

Time::operator*(const double factor)
Time::Time()
Time::~Time(): hours=28, minutes=0
10.0 * qiang: 28 hours, 0 minutes

Time::~Time(): hours=28, minutes=0
Time::~Time(): hours=4, minutes=11
Time::~Time(): hours=2, minutes=48
Time::~Time(): hours=3, minutes=35
请按任意键继续. . .

1.2. Overloading the << Operator (重载 << 运算符)

One very useful feature of classes is that you can overload the << operator so that you can use it with std::cout to display an object’s contents.
可以对 << 运算符进行重载,使之能与 std::cout 一起来显示对象的内容。

Suppose qiang is a Time object. To display Time values, we’ve been using Show().
假设 qiang 是一个 Time 对象。为显示 Time 的值,前面使用的是 Show()

如果可以像下面这样操作将更好:

std::cout << qiang << std::endl;

You can do this because << is one of the C++ operators that can be overloaded. Recall that std::cout is an std::ostream object and that it is smart enough to recognize all the basic C++ types. That’s because the std::ostream class declaration includes an overloaded operator<<() definition for each of the basic types. That is, one definition uses an int argument, one uses a double argument, and so on. So one way to teach cout to recognize a Time object is to add a new function operator definition to the std::ostream class declaration. But it’s a dangerous idea to alter the std::ostream file and mess around with a standard interface. Instead, use the Time class declaration to teach the Time class how to use std::cout.
<< 是可被重载的 C++ 运算符之一。最初,<< 运算符是 C 和 C++ 的位运算符,将值中的位左移。std::ostream 类对该运算符进行了重载,将其转换为一个输出工具。std::cout 是一个 std::ostream 对象,它能够识别所有的 C++ 基本类型。这是因为对于每种基本类型,std::ostream 类声明中都包含了相应的重载的 operator<<() 定义。因此,要使 std::cout 能够识别 Time 对象,一种方法是将一个新的函数运算符定义添加到 std::ostream 类声明中。但修改 std::ostream 文件是个危险的主意,这样做会在标准接口上浪费时间。相反,通过 Time 类声明来让 Time 类知道如何使用 std::cout

1.2.1. << 的第一种重载版本

To teach the Time class to use std::cout, you can use a friend function. Because a statement like the following uses two objects, with the std::ostream class object (std::cout) first
要使 Time 类知道使用 std::cout,必须使用友元函数。下面这样的语句使用两个对象,其中第一个是 std::ostream 类对象 std::cout

std::cout << qiang;

If you use a Time member function to overload <<, the Time object would come first, as it did when you overloaded the * operator with a member function. That means you would have to use the << operator this way.
如果使用一个 Time 成员函数来重载 <<Time 对象将是第一个操作数,就像使用成员函数重载 * 运算符那样。这意味着必须这样使用 <<

qiang << std::cout;  // if operator<<() were a Time member function

This would be confusing. But by using a friend function, you can overload the operator this way.
这样会令人迷惑。但通过使用友元函数,可以像下面这样重载运算符:

void operator<<(std::ostream & os, const Time & time) {
	os << time.hours << " hours, " << time.minutes << " minutes";
}

这样可以使用下面的语句:

std::cout << qiang;

The new Time class declaration makes the operator<<() function a friend function to the Time class. But this function, although not inimical to the ostream class, is not a friend to that class. The operator<<() function takes an std::ostream argument and a Time argument, so it might seem that this function has to be a friend to both classes. If you look at the code for the function, however, you’ll notice that the function accesses individual members of the Time object but only uses the std::ostream object as a whole. Because operator<<() accesses private Time object members directly, it has to be a friend to the Time class. But because it does not directly access private std::ostream object members, the function does not have to be a friend to the std::ostream class. That’s nice because it means you don’t have to tinker with the std::ostream definition.
新的 Time 类声明使 operatro<<() 函数成为 Time 类的一个友元函数。但该函数不是 std::ostream 类的友元,尽管对 std::ostream 类并无害处。operator<<() 函数接受一个 std::ostream 参数和一个 Time 参数,因此表面看来它必须同时是这两个类的友元。然而,看看函数代码就会发现,尽管该函数访问了 Time 对象的各个成员,但从始至终都将 std::ostream 对象作为一个整体使用。因为 operator<<() 直接访问 Time 对象的私有成员,所以它必须是 Time 类的友元。但由于它并不直接访问 std::ostream 对象的私有成员,所以并不一定必须是 std::ostream 类的友元。这很好,因为这就意味着不必修订 std::ostream 的定义。

Note that the new operator<<() definition uses the std::ostream reference std::ostream & os as its first argument. Normally, std::ostream & os refers to the std::cout object. But you could use the operator with other std::ostream objects, in which case os would refer to those objects.
注意,新的 operator<<() 定义使用 std::ostream 引用 std::ostream & os 作为它的第一个参数。通常情况下,std::ostream & os 引用 std::cout 对象。但也可以将这个运算符用于其他 std::ostream 对象,在这种情况下,std::ostream & os 将引用相应的对象。

Another std::ostream object is std::cerr, which routes output to the standard error stream, which, by default, is the display. But in Unix, Linux, and the Windows Command Line environment you can redirect the standard error stream to a file. Through the magic of inheritance , std::ofstream objects can use std::ostream methods. Thus you can use the operator<<() definition to write Time data to files as well as to the screen. You just pass a suitably initialized std::ofstream object instead of std::cout as the first argument.
另一个 std::ostream 对象是 std::cerr,它将输出发送到标准输出流,默认为显示器,但在 UNIX、Linux 和 Windows 命令行环境中,可将标准错误流重定向到文件。std::ofstream 对象可用于将输出写入到文件中。通过继承,std::ofstream 对象可以使用 std::ostream 的方法。可以用 operator<<() 定义来将 Time 的数据写入到文件和屏幕上,为此只需传递一个经过适当初始化的 std::ofstream 对象,而不是 std::cout 对象。

The call std::cout << trip should use the std::cout object itself, not a copy, so the function passes the object as a reference instead of by value. Thus, the expression std::cout << qiang; causes std::ostream & os to be an alias for std::cout, and the expression std::cerr << qiang; causes std::ostream & os to be an alias for std::cerr. The Time object can be passed by value or by reference because either form makes the object values available to the function. Again, passing by reference uses less memory and time than passing by value.
调用 std::cout << trip 应使用 std::cout 对象本身,而不是它的拷贝,因此该函数按引用 (而不是按值) 来传递该对象。这样,表达式 std::cout << qiang; 将导致 std::ostream & os 成为 std::cout 的一个别名,而表达式 std::cerr << qiang; 将导致 std::ostream & os 成为 std::cerr 的一个别名。Time 对象可以按值或按引用来传递,因为这两种形式都使函数能够使用对象的值。按引用传递使用的内存和时间都比按值传递少。

1.2.2. << 的第二种重载版本

Statements such as this work fine:

std::cout << qiang;

But the implementation doesn’t allow you to combine the redefined << operator with the ones std::cout normally uses
但这种实现不允许像通常那样将重新定义的 << 运算符与 std::cout 一起使用:

std::cout << yong << "; " << qiang << std::endl;

要理解这样做不可行的原因以及必须如何做才能使其可行,首先需要了解关于 std::cout 操作的一点知识。

int x = 5;
int y = 8;
std::cout << x << y;

C++ 从左至右读取输出语句,意味着它等同于:

(std::cout << x) << y;

The << operator, as defined in std::iostream, takes an std::ostream object to its left. Clearly, the expression std::cout << x satisfies that requirement because std::cout is an std::ostream object. But the output statement also requires that the whole expression (std::cout << x) be a type std::ostream object because that expression is to the left of << y. Therefore, the std::ostream class implements the operator<<() function so that it returns a reference to an std::ostream object. In particular, it returns a reference to the invoking object std::cout, in this case. Thus, the expression (std::cout << x) is itself the std::ostream object std::cout, and it can be used to the left of the << operator.
正如 std::iostream 中定义的那样,<< 运算符要求左边是一个 std::ostream 对象。显然,因为 std::coutstd::ostream 对象,所以表达式 std::cout << x 满足这种要求。然而,因为表达式 std::cout << x 位于 << y 的左侧,所以输出语句也要求该表达式是一个 std::ostream 类型的对象。因此,std::ostream 类将 operator<<() 函数实现为返回一个指向 std::ostream 对象的引用。具体地说,它返回一个指向调用对象 (这里是 std::cout) 的引用。因此,表达式 (std::cout << x) 本身就是 std::ostream 对象 std::cout,从而可以位于 << 运算符的左侧。

You can take the same approach with the friend function. You just revise the operator<<() function so that it returns a reference to an std::ostream object.
可以对友元函数采用相同的方法。只要修改 operator<<() 函数,让它返回 std::ostream 对象的引用即可:

std::ostream & operator<<(std::ostream & os, const Time & time) {
	os << time.hours << " hours, " << time.minutes << " minutes";
	return os;
}

Note that the return type is std::ostream &. Recall that this means that the function returns a reference to an std::ostream object. Because a program passes an object reference to the function to begin with, the net effect is that the function’s return value is just the object passed to it.
注意,返回类型是 std::ostream &。这意味着该函数返回 std::ostream 对象的引用。因为函数开始执行时,程序传递了一个对象引用给它,这样做的最终结果是,函数的返回值就是传递给它的对象。

std::cout << qiang; 将被转换为 operator<<(std::cout, qiang);

And that call returns the std::cout object. So now the following statement does work:

std::cout << "Trip time: " << trip << " (Tuesday)\n";

First, the following invokes the particular std::ostream definition of << that displays a string and returns the std::cout object:

std::cout << "Trip time: "

So the expression std::cout << "Trip time: " displays the string and then is replaced by its return value, std::cout. 原来的语句被简化为下面的形式:

std::cout << trip << " (Tuesday)\n";

Next, the program uses the Time declaration of << to display the trip values and to return the std::cout object again. This reduces the statement to the following:

std::cout << " (Tuesday)\n";

The program now finishes up by using the std::ostream definition of << for strings to display the final string.
程序使用 std::ostream 中用于字符串的 << 定义,来显示最后一个字符串,并结束运行。

This version of operator<<() also can be used for file output:

#include <fstream>
...
std::ofstream fout;
fout.open("save_time.txt");

Time trip(12, 40);
fout << trip;

The last statement becomes this:

operator<<(fout, trip);

The properties of class inheritance allow an std::ostream reference to refer to std::ostream objects and to std::ofstream objects.
类继承属性让 std::ostream 引用能够指向 std::ostream 对象和 std::ofstream 对象。

In general, to overload the << operator to display an object of class c_name, you use a friend function with a definition in this form.
一般来说,要重载 << 运算符来显示 class c_name 的对象,可使用一个友元函数,其定义如下:

std::ostream & operator<<(std::ostream & os, const c_name & obj) {
	os << ...;  // display object contents
	return os;
}

It implements the first of these as an inline function because the code is so short. When the definition is also the prototype, as in this case, you use the friend prefix.
第一个友元函数 operator*() 作为内联函数,因为其代码很短。当定义同时也是原型时,要使用 friend 前缀。

You use the friend keyword only in the prototype found in the class declaration. You don’t use it in the function definition unless the definition is also the prototype.
只有在类声明中的原型中才能使用 friend 关键字。除非函数定义也是原型,否则不能在函数定义中使用 friend 关键字。

2. Overloaded Operators: Member Versus Nonmember Functions (重载运算符:作为成员函数还是非成员函数)

For many operators, you have a choice between using member functions or nonmember functions to implement operator overloading. Typically, the nonmember version is a friend function so that it can directly access the private data for a class.
对于很多运算符来说,可以选择使用成员函数或非成员函数来实现运算符重载。一般来说,非成员函数应是友元函数,这样它才能直接访问类的私有数据。

For example, consider the addition operator for the Time class. It has this prototype in the Time class declaration:

// member version
Time operator+(const Time & time) const;

Instead, the class could use the following prototype:

// nonmember version
friend Time operator+(const Time & time1, const Time & time2);

The addition operator requires two operands. For the member function version, one is passed implicitly via the this pointer and the second is passed explicitly as a function argument. For the friend version, both are passed as arguments.
加法运算符需要两个操作数。对于成员函数版本来说,一个操作数通过 this 指针隐式地传递,另一个操作数作为函数参数显式地传递。对于友元版本来说,两个操作数都作为参数来传递。

A nonmember version of an overloaded operator function requires as many formal parameters as the operator has operands. A member version of the same operator requires one fewer parameter because one operand is passed implicitly as the invoking object.
非成员版本的重载运算符函数所需的形参数目与运算符使用的操作数数目相同,而成员版本所需的参数数目少一个,因为其中的一个操作数是被隐式地传递的调用对象。

Either of these two prototypes matches the expression T2 + T3, where T2 and T3 are type Time objects.
这两个原型都与表达式 T2 + T3 匹配,其中 T2T3 都是 Time 类型对象。

That is, the compiler can convert the statement

T1 = T2 + T3;

to either of the following (转换为下面两个的任何一个):

T1 = T2.operator+(T3);  // member function
T1 = operator+(T2, T3);  // nonmember function

Keep in mind that you must choose one or the other form when defining a given operator, but not both. Because both forms match the same expression, defining both forms is an ambiguity error, leading to a compilation error.
在定义运算符时,必须选择其中的一种格式,而不能同时选择这两种格式。因为这两种格式都与同一个表达式匹配,同时定义这两种格式将被视为二义性错误,导致编译错误。

For some operators, as mentioned earlier, the member function is the only valid choice. Otherwise, it often doesn’t make much difference. Sometimes, depending on the class design, the nonmember version may have an advantage, particularly if you have defined type conversions for the class.
对于某些运算符来说,成员函数是唯一合法的选择。在其他情况下,这两种格式没有太大的区别。根据类设计,使用非成员函数版本可能更好,尤其是为类定义类型转换时。

References

[1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/
[2] C++ Primer Plus, 6th Edition, https://www.informit.com/store/c-plus-plus-primer-plus-9780321776402

  • Introducing Friends
  • Overloaded Operators: Member Versus Nonmember Functions
  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yongqiang Cheng

梦想不是浮躁,而是沉淀和积累。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值