【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

算术符重载是类的有一个特性,但是每个人使用的方法不一样。用的好,则事半功倍;但是如果不正确的使用,则会后患无穷。

(1) 简单算术符介绍

那什么是算术符重载呢?我们可以举个例子。一般来说,我们定义两个int类型的变量的话,我们就可应对这两个类型进行加、减、乘、除的操作,同时还能比较判断、打印、数组操作、*号操作等等。那么如果我们想自己定义的类也具有这样的属性,那我们应该怎么办呢?当然就要算术符重载了。首先,我们对基本class做一个定义:

class desk
{
public:int price;desk(int value):price(value) {}~desk() {}desk& operator+= (desk& d){this->price += d.price;return *this;}
};

下面,可以用一个范例函数说明一下使用的方法:

74:       desk n(5);
0040126D   push        5
0040126F   lea         ecx,[ebp-10h]
00401272   call        @ILT+0(desk::desk) (00401005)
00401277   mov         dword ptr [ebp-4],0
75:       desk m(10);
0040127E   push        0Ah
00401280   lea         ecx,[ebp-14h]
00401283   call        @ILT+0(desk::desk) (00401005)
00401288   mov         byte ptr [ebp-4],1
76:       n += m;
0040128C   lea         eax,[ebp-14h]
0040128F   push        eax
00401290   lea         ecx,[ebp-10h]
00401293   call        @ILT+40(desk::operator+=) (0040102d)
77:   }

大家可以把重点放在76句上面,不过74、75句我们也会稍微介绍一下:

74句: 创建desk类型的临时变量n,调用构造函数

75句: 创建desk类型的临时变量m,调用构造函数

76句: 两个desk类型的数据相加,但是在汇编的形式上面,我们发现编译器把这段代码解释成函数调用,也就是我们在上面定义的算术符重载函数。

(2)new、free重载

在C++里面,我们不光可以对普通的算术符进行重载处理,还能对new、free进行重载。通过重载new、free,我们还可以加深对代码的认识,正确认识构造、析构、堆内存分配的原理。

首先,我们对new和delete进行重载定义:

class desk
{
public:int price;desk(int value):price(value) {}~desk() {}void* operator new(size_t size) {return malloc(size);}void operator delete (void* pData) { if(NULL != pData) free(pData);}
};

那么使用呢?

72:       desk* d =  new desk(10);
0040127D   push        4
0040127F   call        @ILT+65(desk::operator new) (00401046)
00401284   add         esp,4
00401287   mov         dword ptr [ebp-18h],eax
0040128A   mov         dword ptr [ebp-4],0
00401291   cmp         dword ptr [ebp-18h],0
00401295   je          process+56h (004012a6)
00401297   push        0Ah
00401299   mov         ecx,dword ptr [ebp-18h]
0040129C   call        @ILT+5(desk::desk) (0040100a)
004012A1   mov         dword ptr [ebp-24h],eax
004012A4   jmp         process+5Dh (004012ad)
004012A6   mov         dword ptr [ebp-24h],0
004012AD   mov         eax,dword ptr [ebp-24h]
004012B0   mov         dword ptr [ebp-14h],eax
004012B3   mov         dword ptr [ebp-4],0FFFFFFFFh
004012BA   mov         ecx,dword ptr [ebp-14h]
004012BD   mov         dword ptr [ebp-10h],ecx
73:       delete d;
004012C0   mov         edx,dword ptr [ebp-10h]
004012C3   mov         dword ptr [ebp-20h],edx
004012C6   mov         eax,dword ptr [ebp-20h]
004012C9   mov         dword ptr [ebp-1Ch],eax
004012CC   cmp         dword ptr [ebp-1Ch],0
004012D0   je          process+91h (004012e1)
004012D2   push        1
004012D4   mov         ecx,dword ptr [ebp-1Ch]
004012D7   call        @ILT+0(desk::`scalar deleting destructor') (00401005)
004012DC   mov         dword ptr [ebp-28h],eax
004012DF   jmp         process+98h (004012e8)
004012E1   mov         dword ptr [ebp-28h],0
74:   }

上面是一段普通的new、delete使用代码。但是我们发现,简单的一个语句,在汇编器看来,却需要做这么多的内容,这是为什么呢,我们不妨来自习看一看:

72句:汇编中有两个函数调用,一个是new调用,也就是我们重定义的new函数,一个是构造函数,最后的几行代码主要是把构造函数返回指针赋值给一些临时变量,可忽略

73句:汇编中首先让指针和0进行了判断,然后调用了一个函数,似乎没有调用我们的delete函数,我们可以跟进去看一下:

desk::`scalar deleting destructor':
00401410   push        ebp
00401411   mov         ebp,esp
00401413   sub         esp,44h
00401416   push        ebx
00401417   push        esi
00401418   push        edi
00401419   push        ecx
0040141A   lea         edi,[ebp-44h]
0040141D   mov         ecx,11h
00401422   mov         eax,0CCCCCCCCh
00401427   rep stos    dword ptr [edi]
00401429   pop         ecx
0040142A   mov         dword ptr [ebp-4],ecx
0040142D   mov         ecx,dword ptr [ebp-4]
00401430   call        @ILT+75(desk::~desk) (00401050)
00401435   mov         eax,dword ptr [ebp+8]
00401438   and         eax,1
0040143B   test        eax,eax
0040143D   je          desk::`scalar deleting destructor'+3Bh (0040144b)
0040143F   mov         ecx,dword ptr [ebp-4]
00401442   push        ecx
00401443   call        @ILT+80(desk::operator delete) (00401055)
00401448   add         esp,4
0040144B   mov         eax,dword ptr [ebp-4]
0040144E   pop         edi
0040144F   pop         esi
00401450   pop         ebx
00401451   add         esp,44h
00401454   cmp         ebp,esp
00401456   call        __chkesp (00408810)
0040145B   mov         esp,ebp
0040145D   pop         ebp
0040145E   ret         4

上面的代码便是跟到0x401005之后遇到的代码,这里有一个跳转,真正函数开始的地方是0x401410。这里我们发现函数实际上还是调用了我们定义的delete函数和desk的析构函数。只不过析构函数一定要放在delete调用之前。所以,这里我们就看到了,c++中new的真正含义就是先分配内存,然后调用构造函数;而delete则是先对变量进行析构处理,然后free内存,这就是new和delete的全部意义。掌握了这个基础,可以帮助我们本地对内存进行很好的管理。

(3)friend算术符重载和普通算术符重载的区别

有一种算术符的重载是这样的:

class desk
{int price;
public:desk(int value):price(value) {}~desk() {}friend desk operator+ (desk& d1, desk& d2);
};desk operator +(desk& d1, desk& d2)
{desk d(0);d.price = d1.price + d2.price;return d;
}void process()
{desk d1(3);desk d2(4);desk d = d1 + d2;return;
}

感兴趣的同学可以汇编看一下,找一找它和普通的非友元函数有哪些区别。不过上面的代码还是让我们看出了一些端倪:

a)友元函数不属于类,因为定义的时候我们发现没有desk::这样的前缀

b)友元算术符重载需要比普通的算术符重载多一个输入参数

c)友元函数在进行算术重载定义的时候需要多定义一个临时变量d,这在函数operator+()可以看出来

d)友元算术重载函数会破坏原来类地封装性

e)友元函数实际上就是全局函数

算术运算符使用的经验总结:

(1)算术重载函数是一把双刃剑,务必小心使用

(2)内部算术符函数优先使用于非友元函数

(3)遇到 = 号重载特别注意一下指针

(4)重载的时候函数的内容要和重载的运算符一致,不用重载的是+,实际运算的是相减的内容

(5)除非特别需要重载,负责别重载

(6)重载的时候多复用已经存在的重载运算符

(7)new、delete除了内存管理和测试,一般不重载,全局new、delete严谨重载

(8)相关运算符重载要在stl中使用,务必注意返回值

【预报: 下面博客开始介绍const属性的一些内容】

用汇编的眼光看C++(之算术符重载)相关推荐

  1. 用汇编的眼光看C++(之算术符重载陷阱)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在算术符重载里面,"="重载可能是最经常使用的一种.但是好多人就误以为在函 ...

  2. 用汇编的眼光看C++(之 总结篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 早在八月份的时候,就陆陆续续写了二十多篇用汇编语言看C++的博客内容.在此为了做一个概括,也为 ...

  3. 用汇编的眼光看C++(之拷贝、赋值函数)

    拷贝构造函数和复制函数是类里面比较重要的两个函数.两者有什么区别呢?其实也很简单,我们可以举个例子,加入有这样一个类的定义: [cpp] view plaincopy class apple { pu ...

  4. 用汇编的眼光看C++(之退出流程)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 无论是在判断还是在循环的过程中,通常在遇到合适的条件的时候就会退出相应的模块.跳出模块运行的方 ...

  5. 用汇编的眼光看C++ (之x86汇编)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 说到用汇编的眼光看C++语言,那么怎么阅读汇编代码就成了我们需要解决的一个问题.其实,实话说, ...

  6. 从汇编的眼光看C++(之delete内存泄露)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 有过C语言编程的朋友大多知道,如果在malloc内存之后不及时free掉内存,那么很有可能会造 ...

  7. 用汇编的眼光看c++(之模板函数)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]  如果说模板类定义的是一种数据类型,那么模板函数定义的就是一种函数.既然是函数,那么就有输入数 ...

  8. 从汇编的眼光看C++(之泛型编程)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 泛型编程其实不难.本质上说,泛型编程就是让通用的算法应用到所有的数据类型.具体来说,int是我 ...

  9. 用汇编的眼光看C++(之判断流程)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在我们平常的编程当中,用于判断的地方很多,但主要有下面三种方式:if-else:switch: ...

最新文章

  1. python保留字分支结构_Python基础语法----缩进、注释、命名与保留字、数据类型、分支语句、函数...
  2. 获取treeview中当前鼠标所指的节点treenode 。
  3. 华为云计算玉溪总经理_华为云计算(6)——FusionAccess
  4. QT对象树、信号和槽机制
  5. 八、VueJs 填坑日记之参数传递及内容页面的开发
  6. 第四章 生命周期函数--35 vue-resource发起get、post、jsonp请求
  7. Linux C++ glog日志库的简单使用
  8. JavaScript学习(四十五)—练习题
  9. C语言实现读取elf文件某section
  10. 【电子元件】稳压(齐纳)管 Zener Diode
  11. Hadoop面试题及参考答案
  12. ERstudio导入mysql脚本生成rtf文档
  13. package.json配置简介
  14. MAC系统中安装labelme
  15. codeforces 136A(Presents) Java
  16. python单核运行_python下多核,单核CPU对于并行,并发执行效率的对比-Go语言中文社区...
  17. 《低代码指南100解决方案》——5疫情防控常态化之下,如何做好访客管理?
  18. python中函数的使用
  19. [笔试] 搜狗校招哈尔滨,武汉站 - 实现加减乘操作
  20. 在ubuntu中运行sudo apt-get update报错The following signatures couldn‘t be verified because the public key

热门文章

  1. 一个核物理学霸为何两次收到BlackHat的邀请
  2. TOOLS STORE OPENCART 2.X 主题模板 ABC-0628
  3. 从C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\mt.exe返回错误
  4. 堆排序的Python实现
  5. CVS/SVN/GIT
  6. 第 10 章 数组和指针
  7. Could not find leader nimbus
  8. 随机获取一个集合(List, Set,Map)中的元素转
  9. 洛谷P2073 送花 [2017年6月计划 线段树01]
  10. 20145239杜文超 《Java程序设计》第7周学习总结