• 20、C++ Primer 4th 笔记,重载运算符(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.

  • 相关阅读:
    以淘宝商品搜索漫谈查询条件的排序对效率的影响(SQL查询性能优化,附调优(性能诊断)DMV)
    监测ASP.NET MVC网站
    在WCF中使用Ninject轻量级IOC框架 之 SOAP风格服务
    敏捷——SCRUM
    《scrum敏捷软件开发》读书笔记
    【双旦献礼】PortalBasic Java Web 应用开发框架 v3.0.1 正式发布(源码、示例及文档)
    前端架构
    Android源码学习之如何使用eclipse+NDK
    mass Framework attr模块 v3
    【转】iOS 6版本与之前版本差异总结
  • 原文地址:https://www.cnblogs.com/mydomain/p/1996295.html
Copyright © 2020-2023  润新知