20、C++ Primer 4th 笔记,重载运算符(1)

简介: 1、除了函数调用符之外,重载操作符的形参数目(包括成员函数的隐式this指针)与操作符的操作数目相同。函数调用操作符可以接受任意数目的操作数。 表1 可重载的操作符名 + - * / % ^ & | ...

1、除了函数调用符之外,重载操作符的形参数目(包括成员函数的隐式this指针)与操作符的操作数目相同。函数调用操作符可以接受任意数目的操作数。

1 可重载的操作符名

+

-

*

/

%

^

&

|

~

!

,

=

<

>

<=

>=

++

--

<<

>>

==

!=

&&

||

+=

-=

/=

%=

^=

&=

|=

*=

<<=

>>=

[]

()

->

->*

new

new[]

delete

delete []

2 不能重载的操作符

::

.*

.

?:

不能通过连接其他合法符号来创建任何新的操作符。

2重载操作符必须具有一个类类型/枚举类型操作数。不能改变内置操作符原有的优先级和结合性。除了函数调用操作符operator()之外,重载操作符时使用默认实参是非法的。

3、作为成员函数的操作符有一个隐含的this指针,限定为第一个操作数

4、一般将算术和关系操作符定义为非成员函数,而将赋值操作符定义为成员。

5、加返回右值,而复合赋值返回对左操作数引用

6、重载的设计

1)不要重载具有内置含义的操作符

赋值操作符(可定义自己的)、取地址操作符和逗号操作符对类类型操作数有默认含义。内置逻辑与(&&)和逻辑或(||)操作符使用短路求值,如果重新定义该操作符,将失去操作符的短路求值特征。

2)用作关联容器键类型的类就有<操作符,顺序容器中应定义==操作符。为了相应算法操作的方便。如sort,find等。

3)总结

• 赋值(=)、下标([])、调用(())和成员访问箭头(->)等操作符必须定义为成员,将这些操作符定义为非成员函数将在编译时标记为错误。

• 像赋值一样,复合赋值操作符通常应定义为类的成员,与赋值不同的是,不一定非得这样做,如果定义非成员复合赋值操作符,不会出现编译错误。

• 改变对象状态或与给定类型紧密联系的其他一些操作符,如自增、自减和解引用,通常就定义为类成员。

对称的操作符,如算术操作符、相等操作符、关系操作符和位操作符,最好定义为普通非成员函数。

7、重载操作符的定义示例

1)输出<<

示例

ostream& operator<<(ostream& os, const ClassType *object)
{
    //...
	os << //...
	return os;
}

通常所做格式化应尽量少。

IO操作符必须为非成员函数,否则会出现 item << cout的这种不自然情形。

2)输入>>

输入操作符必须处理错误和文件结束的可能性。

示例

istream& operator>>(istream& in, Sales_Item& s)
{
	double price;
	in >> s.isbn >> s.units_sold >> price;
	if (in)
		s.revenue = s.units_sold * price;
	else
		s = Sales_item(); //input failed:reset object to default state
	return in;
}

   通常输入操作符仅需设置failbit,设置eofbit意思是文件耗尽,设置badbit指出流被破坏。

3)算术操作符和关系操作符

示例

Sales_item operator+(const Salse_item& lhs, const Salse_item& rhs)
{
	Sales_item ret(lhs);
	ret += rhs;  //非常好用的方法
	return ret;
}

4)相等操作符与不等操作符一起实现

示例

inline bool
operator==(const ClassType &lhs, const ClassType &rhs)
{
	return ...
}
inline bool
operator!=(const ClassType &lhs, const ClassType &rhs)
{
	return !(lhs == rhs);
}

5)一般而言,赋值操作符与复合赋值操作符应返回左操作数的引用(*this)

6)下标操作符

定义两个版本:一个为非const成员并返回引用,另一个为const成员并返回const引用。

示例

class Foo
{
public:
	int &operator[](const size_t);
	const int &operator[](const size_t) const;
	//...
private:
	vector<int> data;
};

int& Foo::operator[](const size_t index)
{
	return data[index]; //注意,这里没有进行下标越界检查
}
const int& Foo::operator [](const size_t index) const
{
	return data[index];
}

7)成员访问操作符

同样,也是两个版本。

重载箭头操作符必须返回指向类类型的指针,或返回定义了自己的箭头操作符的类类型对象(或引用)

示例

#include "iostream"
#include "stdio.h"
using namespace std;
class ScreenPtr;
class Screen //用于ScreenPtr中操作对象的类
{
public:
	Screen()
	{
		cout << "In Screen" << endl;
	}
	void display()
	{
		cout << "In Screen Display" << endl;
	}
};
class ScrPtr //智能指针,用来管理ScreenPtr类中要操作对象的类的指针
{
	friend class ScreenPtr;
	Screen *sp;
	size_t use;
	ScrPtr(Screen *p):sp(p), use(1) {}
	~ScrPtr() 
	{
		delete sp;
	}
};

class ScreenPtr
{
public:
	ScreenPtr(Screen *p):ptr(new ScrPtr(p)) {}
	ScreenPtr(const ScreenPtr &orig):ptr(orig.ptr) //复制构造函数
	{
		++ptr->use;
	}
	ScreenPtr& operator=(const ScreenPtr&){}
	~ScreenPtr()
	{
		if (--ptr->use == 0)
		{
		delete ptr;
		}
		cout << "In ScreenPtr" << endl;
	}
public:
	Screen& operator*()
	{
		return *ptr->sp;
	}
	Screen* operator->()
	{
		return ptr->sp;
	}
	const Screen& operator*() const
	{
		return *ptr->sp;
	}
	const Screen* operator->() const
	{
		return ptr->sp;
	}
private:
	ScrPtr *ptr;
};

int main()
{
	Screen *myscreen = new Screen();
	ScreenPtr p(myscreen);
	p->display();
	return 0;
}

说明:point->action();

1.If point is a pointer to a class object that has a member named action , then

the compiler writes code to call the action member of that object.

2.Otherwise, if point is an object of a class that defines operator-> , then

point->action is the same as point.operator->()->action . That is, we execute

operator->() on point and then repeat these three steps, using the result of

executing operator-> on point .

3. Otherwise, the code is in error.

目录
相关文章
|
3月前
|
C++
【C++基础】运算符详解
这篇文章详细解释了C++中运算符的用法,包括算术运算符、赋值运算符、比较运算符和逻辑运算符,以及它们在表达式中的作用和示例。
30 2
|
3月前
|
C++
C++(十九)new/delete 重载
本文介绍了C++中`operator new/delete`重载的使用方法,并通过示例代码展示了如何自定义内存分配与释放的行为。重载`new`和`delete`可以实现内存的精细控制,而`new[]`和`delete[]`则用于处理数组的内存管理。不当使用可能导致内存泄漏或错误释放。
|
4月前
|
C++
c++学习笔记02 运算符
C++学习笔记,介绍了C++中的运算符,包括基本的加减乘除、求模、前后置递增递减、赋值运算符、比较运算符和逻辑运算符的使用及其注意事项。
41 6
|
4月前
|
C++ 容器
【C/C++笔记】迭代器
【C/C++笔记】迭代器
27 1
|
4月前
|
存储 安全 程序员
【C/C++笔记】迭代器范围
【C/C++笔记】迭代器范围
68 0
|
5月前
|
NoSQL 编译器 Redis
c++开发redis module问题之如果Redis加载了多个C++编写的模块,并且它们都重载了operator new,会有什么影响
c++开发redis module问题之如果Redis加载了多个C++编写的模块,并且它们都重载了operator new,会有什么影响
|
5月前
|
C++ Windows
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
在Windows上使用Visual Studio 2022进行FFmpeg和SDL2集成开发,首先安装FFmpeg至E:\msys64\usr\local\ffmpeg,然后新建C++控制台项目。在项目属性中,添加FFmpeg和SDL2的头文件及库文件目录。接着配置链接器的附加依赖项,包括多个FFmpeg及SDL2的lib文件。在代码中引入FFmpeg的`av_log`函数输出"Hello World",编译并运行,若看到"Hello World",即表示集成成功。详细步骤可参考《FFmpeg开发实战:从零基础到短视频上线》。
182 0
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
|
5月前
|
存储 C++
【C++】string类的使用③(非成员函数重载Non-member function overloads)
这篇文章探讨了C++中`std::string`的`replace`和`swap`函数以及非成员函数重载。`replace`提供了多种方式替换字符串中的部分内容,包括使用字符串、子串、字符、字符数组和填充字符。`swap`函数用于交换两个`string`对象的内容,成员函数版本效率更高。非成员函数重载包括`operator+`实现字符串连接,关系运算符(如`==`, `&lt;`等)用于比较字符串,以及`swap`非成员函数。此外,还介绍了`getline`函数,用于按指定分隔符从输入流中读取字符串。文章强调了非成员函数在特定情况下的作用,并给出了多个示例代码。
|
5月前
|
NoSQL Redis C++
c++开发redis module问题之避免多个C++模块之间因重载operator new而产生的冲突,如何解决
c++开发redis module问题之避免多个C++模块之间因重载operator new而产生的冲突,如何解决