Introduction


一、函数重载

关于重载 Overloading,最基本的是根据以下两个特性:

 - 基于参数

 - 基于const

其实,函数重载也没啥多余值得说的东西。

二、自定义操作规则

c++的操蛋属性:自己为一档,空一档,其他随意。

  1. UB_stack a;
  2. UB_stack b = a; // copy
  3. auto c = a;
  4. auto d {a};   // (or auto d = {a}), deduced type is std::initializer_list

这是一个抓狂的问题,详见:http://scottmeyers.blogspot.com.au/2014/03/if-braced-initializers-have-no-type-why.html

Goto: C++11:std::initializer_list

大神的无奈

今日一乐:为何感觉到了Scott对chinese edition是黑白版本的好奇和无奈。

三、可重载 or 不可重载

Goto: C++ 重载运算符和重载函数

下面是:可重载的运算符列表

双目算术运算符 + (加),-(减),*(乘),/(除),% (取模)
关系运算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符 ||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符 + (正),-(负),*(指针),&(取地址)
自增自减运算符 ++(自增),--(自减)
位运算符 | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符 =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放 new, delete, new[ ] , delete[]
其他运算符 ()(函数调用),->(成员访问),,(逗号),[](下标)

下面是:不可重载的运算符列表

成员访问运算符 .
成员指针访问运算符 .*, ->*
域运算符 ::
长度运算符 sizeof
条件运算符 ?
预处理符号 #

Overloaded Operator


==

Ref: C++ 关系运算符重载

声明关键字 operator,以及紧跟其后的一个c++预定义的操作符,举例如下:

  1. // 申明关键字
    class person{
  2. private:
  3. int age;
  4. public:
  5. person(int a){
  6. this->age=a;
  7. }
  8. inline bool operator == (const person &ps) const;
  9. };
  10.  
  11. // 实现方式如下
  12. inline bool person::operator == (const person &ps) const
  13. {
  14. if (this->age==ps.age)  // 这里的this看上去是“符号”左边的类
  15. return true;
  16. return false;
  17. }
  18.  
  19. int main()
  20. {
  21. person p1();
  22. person p2();
  23. if(p1==p2) cout<<”the age is equal!”< return ;
  24. }

>>,  <<,  +,  +=

包括:(1) 输入输出;(2) 自增自减;(3) 运算.

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <iterator>
  5. #include <UB_stack.h>
  6.  
  7. using namespace std;
  8.  
  9. class Test {
  10. public:
  11. Test(int x, int y):a{x},b{y}{}
  12.  
  13. // The output operator must be defined as a friend function
  14. // and is usually a non-member function.
  15. // The input operator is similar.
  16. friend ostream& operator << (ostream&, const Test &);
  17. friend istream& operator >> (istream&, Test&);
  18. friend Test operator +(const Test&, const Test&);// Usually implemented as a member function.
  19. Test& operator += (const Test &);
  20.  
  21. int returnA(void);
  22. void init(void);
  23.  
  24. private:
  25. int a;
  26. int b;
  27. };
  28.  
  29. /******************************************************************************/
  30.  
  31. void Test::init(void)
  32. {
  33. this->a = ;
  34. this->b = ;
  35. }
  36.  
  37. int Test::returnA(void)
  38. {
  39. return (this->a);
  40. }
  41.  
  42. ostream& operator << (ostream &os, const Test &t)
  43. {
  44. os << t.a << " " << t.b << endl;
  45. }
  46.  
  47. istream& operator >> (istream &is, Test &t)
  48. {
  49. is >> t.a >> t.b;
  50. }
  51.  
  52. Test& Test::operator += (const Test &t)
  53. {
  54. this->a += t.a;
  55. this->b += t.b;
  56.  
  57. return *this;
  58. }
  59.  
  60. Test operator + (const Test &t1, const Test &t2)
  61. {
  62. Test ret = t1;
  63. ret += t2;
  64. return ret;
  65. }
  66.  
  67. /******************************************************************************/
  68.  
  69. class SmallInt {
  70. public:
  71. friend ostream& operator << (ostream &os, const SmallInt &s);
  72. friend bool operator < (const SmallInt&, const SmallInt&);
  73. SmallInt(int v): value_{v} {}
  74. private:
  75. int value_;
  76. };

  77. // friend function.
  78. bool operator < (const SmallInt &rhs,const SmallInt &lhs) {
  79. return rhs.value_ <= lhs.value_;
  80. }

  81. // friend function
  82. std::ostream& operator<<(std::ostream &os, const SmallInt &s) {
  83. os << s.value_;
  84. return os;
  85. }
  86.  
  87. /******************************************************************************/
  88.  
  89. int main()
  90. {
  91. cout << "Hello World!" << endl;
  92.  
  93. Test t1{, };
  94. Test t2{, };
  95.  
  96. /*
  97. * I/O Operators
  98. */
  99. cout << t1 << t2;
  100. cin >> t2;
  101. cout << t1 << t2;
  102.  
  103. t1.init();
  104. t2.init();
  105.  
  106. /*
  107. * Compound Assignment Operators
  108. */
  109. t2 += t1;
  110. cout << t2;
  111.  
  112. /*
  113. * Arithmetic Operators
  114. */
  115. cout << t1+t2;
  116.  
  117. /*
  118. * Relational Operators
  119. * ...
  120. */
  121.  
  122. /*
  123. * Using the STL Sort and Copy Algorithms
  124. */
  125. vector<SmallInt> vec{SmallInt{}, SmallInt{}, SmallInt{}};
  126.  
  127. sort(vec.begin(), vec.end());
  128. copy(vec.begin(), vec.end(), std::ostream_iterator<SmallInt>(std::cout, " "));
  129.  
  130. return ;
  131. }

加法运算符重载 de 返回值

函数直接返回类,以为着什么?

会直接调用拷贝构造函数,然后默认实施的是:逐位拷贝语义.

Ref: C++进阶系列:拷贝构造函数与NRV优化

Ref: 关于NRV优化[例子非常不粗]

请问从a, b传入函数开始,一共创建了多少个对象?

  1. Vector a, b;
  2. Vector c = add(a, b);

操作符重载 与 友元函数

C++操作符重载形式——成员函数or友元函数

一般来说,C++运算符重载可采用成员函数和友元函数,二者都可以访问类的私有成员,那么该采用哪一种呢?

(1)当重载为成员函数时,会隐含一个this指针;当重载为友元函数时,不存在隐含的this指针,需要在参数列表中显示地添加操作数。

上述的代码中,因为用了fridend函数,因此没有用this,所以一元运算符重载 "用到了两个参数".

(2)当重载为成员函数时,只允许右参数的隐式转换;当重载为友元函数时,能够接受左参数和右参数的隐式转换。

如果采用成员函数形式CString::operator+(const CString& rhs),则只能接受CString+char;

如果执行char+CString则会编译出错。

简单类型可以"隐式转换"为复杂类型.

  1. class CString
  2. {
  3. public:
  4. CString(char* str);
  5. private:
  6. char* m_pStr;
  7. };

一般而言,对于双目运算符,最好将其重载为友元函数;而对于单目运算符,则最好重载为成员函数。

但是也存在例外情况。有些双目运算符是不能重载为友元函数的,比如 赋值运算符=、函数调用运算符()、下标运算符[]、指针运算符-> 等,因为这些运算符在语义上与this都有太多的关联。

比如=表示“将自身赋值为…”,[]表示“自己的第几个元素”,如果将其重载为友元函数,则会出现语义上的不一致。

赋值运算符 =

实际操作当中,调用的是:拷贝构造函数。

返回void,只是”赋值“的简单版本:https://www.runoob.com/cplusplus/assignment-operators-overloading.html

函数调用运算符 ()

也叫做:functor

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <thread>
  4. #include <functional>
  5. #include <iostream>
  6. #include <stdio.h>
  7. #include <algorithm>
  8.  
  9. using namespace std;
  10.  
  11. struct Sum_t
  12. {
  13. Sum_t(int * t):total(t)
  14. {};
  15.  
  16. int * total;
  17.  
  18. void operator () (int element)
  19. {
  20. *total+=element;
  21. }
  22. };
  23.  
  24. int main()
  25. {
  26. int total = ;
  27. Sum_t s(&total);  // <-- 这个是构造参数
  28.  
  29. int arr[] = {, , , , , };
  30.  
  31. std::for_each(arr, arr+, s); // <-- 类作为函数来使用
  32. cout << total << endl;
  33. }

下标运算符 []

假设 X 是某一个类的对象,类中定义了重载“[ ]”的 operator[ ] 函数,则表达式:

  1. X[Y];
  2.  
  3. 可被解释为:
  4.  
  5. X.operator[](Y);

定义实例:

  1. class SafeArray {
  2. public:
  3. SafeArray(int s);
  4. SafeArray(const int v[], int s);
  5. ~SafeArray() {delete[] values;}
  6.  
  7. int& operator [] (int i);
  8. int operator [] (int i) const;
  9.  
  10. private:
  11. int size;
  12. int *values;
  13. };

  14. // 构造函数的实现
  15. SafeArray::SafeArray(int s) : size{s}, values{new int[size]} {}
  16. SafeArray::SafeArray(const int v[], int s) : size{s}
  17. {
  18. values = new int[size];
  19. for (int i = ; i < size; i++)
  20. {
  21. values[i] = v[i];
  22. }
  23. }

  24. // 符号重载的实现
  25. int& SafeArray::operator [](int index) {
  26. assert((index >= 0) && (index < size));
  27. return values[index];
  28. }
  29.  
  30. int SafeArray::operator [](int index) const {  // 常函数不能修改 函数内的成员,不能用于右赋值.
  31. assert((index >= 0) && (index < size));
  32. return values[index];
  33. }

使用样例:

  1. SafeArray s{};
  2. // s[12] = 2; // 这算是两个operator,因为是有赋值运算,必须返回&类型.
  3. cout << s[] << endl;

自增自减符 ++, --

后缀法加了一个参数,有点意思。

From: https://www.runoob.com/cplusplus/increment-decrement-operators-overloading.html

  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class Time
  5. {
  6. private:
  7. int hours; // 0 到 23
  8. int minutes; // 0 到 59
  9. public:
  10. // 所需的构造函数
  11. Time(){
  12. hours = ;
  13. minutes = ;
  14. }
  15. Time(int h, int m){
  16. hours = h;
  17. minutes = m;
  18. }
  19. // 显示时间的方法
  20. void displayTime()
  21. {
  22. cout << "H: " << hours << " M:" << minutes <<endl;
  23. }
  24. // 重载前缀递增运算符( ++x )
  25. Time operator ++ ()
  26. {
  27. ++minutes; // 对象加 1
  28. if(minutes >= )
  29. {
  30. ++hours;
  31. minutes -= ;
  32. }
  33. return Time(hours, minutes);
  34. }
  35. // 重载后缀递增运算符( x++ )
  36. Time operator ++ (int)
  37. {
  38. // 保存原始值
  39. Time T(hours, minutes);
  40. // 对象加 1
  41. ++minutes;
  42. if(minutes >= )
  43. {
  44. ++hours;
  45. minutes -= ;
  46. }
  47. // 返回旧的原始值
  48. return T;
  49. }
  50. };
  51.  
  52. -------------------------------------------------------------
  53. int main()
  54. {
  55. Time T1(, ), T2(,);
  56.  
  57. ++T1; // T1 加 1
  58. T1.displayTime(); // 显示 T1
  59. ++T1; // T1 再加 1
  60. T1.displayTime(); // 显示 T1
  61.  
  62. T2++; // T2 加 1
  63. T2.displayTime(); // 显示 T2
  64. T2++; // T2 再加 1
  65. T2.displayTime(); // 显示 T2
  66. return ;
  67. }

指针相关的,比较复杂,但不经常用到的运算符重载.

指针运算符 -> , *

/* 感觉用处不是很大 */

Ref: C++ 类成员访问运算符 -> 重载

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. // 假设一个实际的类
  6. class Obj {
  7. static int i, j;
  8. public:
  9. void f() const { cout << i++ << endl; }
  10. void g() const { cout << j++ << endl; }
  11. };
  12.  
  13. // 静态成员定义
  14. int Obj::i = ;
  15. int Obj::j = ;
  16.  
  17. // 为上面的类实现一个容器
  18. class ObjContainer {
  19. vector<Obj*> a;
  20. public:
  21. void add(Obj* obj)
  22. {
  23. a.push_back(obj); // 调用向量的标准方法
  24. }
  25. friend class SmartPointer;
  26. };
  27.  
  28. // 实现智能指针,用于访问类 Obj 的成员
  29. class SmartPointer {
  30. ObjContainer oc;
  31. int index;
  32. public:
  33. SmartPointer(ObjContainer& objc)
  34. {
  35. oc = objc;
  36. index = ;
  37. }
  38. // 返回值表示列表结束
  39. bool operator++() // 前缀版本
  40. {
  41. if(index >= oc.a.size() - ) return false;
  42. if(oc.a[++index] == ) return false;
  43. return true;
  44. }
  45. bool operator++(int) // 后缀版本
  46. {
  47. return operator++();
  48. }
  49. // 重载运算符 ->
  50. Obj* operator->() const
  51. {
  52. if(!oc.a[index])
  53. {
  54. cout << "Zero value";
  55. return (Obj*);
  56. }
  57. return oc.a[index];
  58. }
  59. };
  60.  
  61. int main() {
  62. const int sz = ;
  63. Obj o[sz];
  64. ObjContainer oc;
  65. for(int i = ; i < sz; i++)
  66. {
  67. oc.add(&o[i]);
  68. }
  69. SmartPointer sp(oc); // 创建一个迭代器
  70. do {
  71. sp->f(); // 智能指针调用
  72. sp->g();
  73. } while(sp++);
  74. return ;
  75. }

类成员访问运算符( -> )可以被重载,但它较为麻烦。它被定义用于为一个类赋予"指针"行为。运算符 -> 必须是一个成员函数。如果使用了 -> 运算符,返回类型必须是指针或者是类的对象。

运算符 -> 通常与指针引用运算符 * 结合使用,用于实现"智能指针"的功能。这些指针是行为与正常指针相似的对象,唯一不同的是,当您通过指针访问对象时,它们会执行其他的任务。比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象。

-> must be a member function and * is usually a member.

(Here 简介)

貌似不错的智能指针的博文:http://www.cnblogs.com/lanxuezaipiao/p/4132096.html

The Basic Idea Behind All Smart Pointers

类型转换操作符

Type Conversion Operators

Conversion operators must be defined as member functions. They
do not take any parameters, nor do they specify a return type.
Typically conversions don’t modify the object and are declared
const.

如果去掉explicit(显式的),则User code中的line 2即可成立。

explicit: 声明为explicit的构造函数,不能在隐式转换中使用。

End.

[c++] Operator overloading的更多相关文章

  1. Operator overloading

    By defining other special methods, you can specify the behavior of operators on user-defined types. ...

  2. [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)

    operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...

  3. Lintcode208 Assignment Operator Overloading (C++ Only) solution 题解

    [题目描述] Implement an assignment operator overloading method. Make sure that: The new data can be copi ...

  4. C# to IL 5 Operator Overloading(操作符重载)

    Every operator overload that we use in C#, gets converted to a function call in IL. Theoverloaded &g ...

  5. 重载操作符 operator overloading 学习笔记

    重载操作符,只是另外一种调用函数的方法和表现方式,在某些情况它可以让代码更简单易读.注意不要过度使用重载操作符,除非它让你的类更简单,让你的代码更易读. 1语法 如下: 其中友元,关键字不是必须的,但 ...

  6. 面向对象程序设计-C++ Operator Overloading & Type conversion (Static)【第十一次上课笔记】

    本次上课继续讲解了 [ ] .-> 等运算符重载的具体例子 也讲解了C++单个参数的类的类型转换的案例 最后稍微提到了 static 的第三种作用:静态数据成员 具体详解我都已注释出来了,大家可 ...

  7. 面向对象程序设计-C++ Default constructor & Copy constructor& Destructor & Operator Overloading【第九次上课笔记】

    先上笔记内容吧: 这次上课的内容有关 构造函数 析构函数 运算符重载 return * this 内容很细,大家好好回顾笔记再照应程序复习吧 :) #include <iostream> ...

  8. 8 Operator overloading

    在类中,Groovy支持你使用标准的操作符.例如,如果你想使用a+b操作(a和b来自于Z类),那么你在Z类中,必须实现(implement)plus(Zname)方法.

  9. c++ operator

    这篇博文是以前很久写的,贴在我的早期一个blog中,今天google一下,发现还真有不少人转载,可惜并不注明出处.那时觉得operator比较好玩.C++有时它的确是个耐玩的东东.operator它有 ...

随机推荐

  1. iOS开发UI高级手势识别器

    ####手势识别器 UIGestureRecognizer类 ·UITapGestureRecognizer(轻击) ·UIPinchGestureRecognizer(捏合) ·UIPanGestu ...

  2. .NET C#-- 利用BeginInvoke与EndInvoke完成异步委托方法并获取方法执行返回值示例

    //定义委托 delegate string MyDelegate(string name); //定义委托调用函数 public string Hello(string name) { Thread ...

  3. USACO翻译:USACO 2013 NOV Silver三题

    USACO 2013 NOV SILVER 一.题目概览 中文题目名称 未有的奶牛 拥挤的奶牛 弹簧牛 英文题目名称 nocow crowded pogocow 可执行文件名 nocow crowde ...

  4. final 评论ii

    按照演讲顺序 1.约跑app         约跑app,从界面的单调,到最后的final发布,实现界面的友好性,有了很大的提高.约跑app,如果在约定地点可以显示出,所在位置,以及约定地址.就可以达 ...

  5. Silverlight 使用DataContractJsonSerializer序列化与反序列化 Json

    环境说明:Silverlight 5.1,.Net Framework  ​4.0 1.添加引用System.ServiceModel.Web.dll. 因为 System.Runtime.Seria ...

  6. 最近在新公司的一些HTML学习

    还是先把代码贴在这  后期再写感想 <!DOCTYPE html> <head> <meta http-equiv="x-ua-compatible" ...

  7. CSS选择器中类和ID选择器的区别

    类和ID选择器的区别 学习了类选择器和ID选择器,我们会发现他们之间有很多的相似处,是不是两者可以通用呢?我们不要着急先来总结一下他们的相同点和不同点: 相同点:可以应用于任何元素不同点: 1.ID选 ...

  8. jQuery中设置form表单中action值与js有什么不同。。。。

    jQuery中设置form表单中action值与js有什么不同.... HTML代码如下: <form action="" method="post" i ...

  9. PostgreSQL的.NET驱动程序Npgsql

    Npgsql是PostgreSQL的一个.NET数据提供程序,它可以自由获取.它可以通过下列选项获得独立的下载,也可以安装PostgreSQL数据库程序时选择安装. 最新的_npgsql2 Npgsq ...

  10. 循序渐进做项目系列(4)迷你QQ篇(2)——视频聊天!(附源码)

    一·效果展示 源码派送:MiniQQ1.1 文字聊天的实现参见:循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天 二·服务端设计 对于实现视频聊天而言,服务端最核心的工作就是要构造多媒 ...