[c++] Operator overloading
Introduction
一、函数重载
关于重载 Overloading,最基本的是根据以下两个特性:
- 基于参数
- 基于const
其实,函数重载也没啥多余值得说的东西。
二、自定义操作规则
c++的操蛋属性:自己为一档,空一档,其他随意。
- UB_stack a;
- UB_stack b = a; // copy
- auto c = a;
- 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
==
声明关键字 operator,以及紧跟其后的一个c++预定义的操作符,举例如下:
- // 申明关键字
class person{- private:
- int age;
- public:
- person(int a){
- this->age=a;
- }
- inline bool operator == (const person &ps) const;
- };
- // 实现方式如下
- inline bool person::operator == (const person &ps) const
- {
- if (this->age==ps.age) // 这里的this看上去是“符号”左边的类
- return true;
- return false;
- }
- int main()
- {
- person p1();
- person p2();
- if(p1==p2) cout<<”the age is equal!”< return ;
- }
>>, <<, +, +=
包括:(1) 输入输出;(2) 自增自减;(3) 运算.
- #include <iostream>
- #include <vector>
- #include <algorithm>
- #include <iterator>
- #include <UB_stack.h>
- using namespace std;
- class Test {
- public:
- Test(int x, int y):a{x},b{y}{}
- // The output operator must be defined as a friend function
- // and is usually a non-member function.
- // The input operator is similar.
- friend ostream& operator << (ostream&, const Test &);
- friend istream& operator >> (istream&, Test&);
- friend Test operator +(const Test&, const Test&);// Usually implemented as a member function.
- Test& operator += (const Test &);
- int returnA(void);
- void init(void);
- private:
- int a;
- int b;
- };
- /******************************************************************************/
- void Test::init(void)
- {
- this->a = ;
- this->b = ;
- }
- int Test::returnA(void)
- {
- return (this->a);
- }
- ostream& operator << (ostream &os, const Test &t)
- {
- os << t.a << " " << t.b << endl;
- }
- istream& operator >> (istream &is, Test &t)
- {
- is >> t.a >> t.b;
- }
- Test& Test::operator += (const Test &t)
- {
- this->a += t.a;
- this->b += t.b;
- return *this;
- }
- Test operator + (const Test &t1, const Test &t2)
- {
- Test ret = t1;
- ret += t2;
- return ret;
- }
- /******************************************************************************/
- class SmallInt {
- public:
- friend ostream& operator << (ostream &os, const SmallInt &s);
- friend bool operator < (const SmallInt&, const SmallInt&);
- SmallInt(int v): value_{v} {}
- private:
- int value_;
- };
// friend function.- bool operator < (const SmallInt &rhs,const SmallInt &lhs) {
- return rhs.value_ <= lhs.value_;
- }
// friend function- std::ostream& operator<<(std::ostream &os, const SmallInt &s) {
- os << s.value_;
- return os;
- }
- /******************************************************************************/
- int main()
- {
- cout << "Hello World!" << endl;
- Test t1{, };
- Test t2{, };
- /*
- * I/O Operators
- */
- cout << t1 << t2;
- cin >> t2;
- cout << t1 << t2;
- t1.init();
- t2.init();
- /*
- * Compound Assignment Operators
- */
- t2 += t1;
- cout << t2;
- /*
- * Arithmetic Operators
- */
- cout << t1+t2;
- /*
- * Relational Operators
- * ...
- */
- /*
- * Using the STL Sort and Copy Algorithms
- */
- vector<SmallInt> vec{SmallInt{}, SmallInt{}, SmallInt{}};
- sort(vec.begin(), vec.end());
- copy(vec.begin(), vec.end(), std::ostream_iterator<SmallInt>(std::cout, " "));
- return ;
- }
加法运算符重载 de 返回值
函数直接返回类,以为着什么?
会直接调用拷贝构造函数,然后默认实施的是:逐位拷贝语义.
Ref: C++进阶系列:拷贝构造函数与NRV优化
Ref: 关于NRV优化[例子非常不粗]
请问从a, b传入函数开始,一共创建了多少个对象?
- Vector a, b;
- Vector c = add(a, b);
操作符重载 与 友元函数
一般来说,C++运算符重载可采用成员函数和友元函数,二者都可以访问类的私有成员,那么该采用哪一种呢?
(1)当重载为成员函数时,会隐含一个this指针;当重载为友元函数时,不存在隐含的this指针,需要在参数列表中显示地添加操作数。
上述的代码中,因为用了fridend函数,因此没有用this,所以一元运算符重载 "用到了两个参数".
(2)当重载为成员函数时,只允许右参数的隐式转换;当重载为友元函数时,能够接受左参数和右参数的隐式转换。
如果采用成员函数形式CString::operator+(const CString& rhs),则只能接受CString+char;
如果执行char+CString则会编译出错。
简单类型可以"隐式转换"为复杂类型.
- class CString
- {
- public:
- CString(char* str);
- private:
- char* m_pStr;
- };
一般而言,对于双目运算符,最好将其重载为友元函数;而对于单目运算符,则最好重载为成员函数。
但是也存在例外情况。有些双目运算符是不能重载为友元函数的,比如 赋值运算符=、函数调用运算符()、下标运算符[]、指针运算符-> 等,因为这些运算符在语义上与this都有太多的关联。
比如=表示“将自身赋值为…”,[]表示“自己的第几个元素”,如果将其重载为友元函数,则会出现语义上的不一致。
赋值运算符 =
实际操作当中,调用的是:拷贝构造函数。
返回void,只是”赋值“的简单版本:https://www.runoob.com/cplusplus/assignment-operators-overloading.html
函数调用运算符 ()
也叫做:functor
- #include <stdio.h>
- #include <string.h>
- #include <thread>
- #include <functional>
- #include <iostream>
- #include <stdio.h>
- #include <algorithm>
- using namespace std;
- struct Sum_t
- {
- Sum_t(int * t):total(t)
- {};
- int * total;
- void operator () (int element)
- {
- *total+=element;
- }
- };
- int main()
- {
- int total = ;
- Sum_t s(&total); // <-- 这个是构造参数
- int arr[] = {, , , , , };
- std::for_each(arr, arr+, s); // <-- 类作为函数来使用
- cout << total << endl;
- }
下标运算符 []
假设 X 是某一个类的对象,类中定义了重载“[ ]”的 operator[ ] 函数,则表达式:
- X[Y];
- 可被解释为:
- X.operator[](Y);
定义实例:
- class SafeArray {
- public:
- SafeArray(int s);
- SafeArray(const int v[], int s);
- ~SafeArray() {delete[] values;}
- int& operator [] (int i);
- int operator [] (int i) const;
- private:
- int size;
- int *values;
- };
// 构造函数的实现- SafeArray::SafeArray(int s) : size{s}, values{new int[size]} {}
- SafeArray::SafeArray(const int v[], int s) : size{s}
- {
- values = new int[size];
- for (int i = ; i < size; i++)
- {
- values[i] = v[i];
- }
- }
// 符号重载的实现- int& SafeArray::operator [](int index) {
- assert((index >= 0) && (index < size));
- return values[index];
- }
- int SafeArray::operator [](int index) const { // 常函数不能修改 函数内的成员,不能用于右赋值.
- assert((index >= 0) && (index < size));
- return values[index];
- }
使用样例:
- SafeArray s{};
- // s[12] = 2; // 这算是两个operator,因为是有赋值运算,必须返回&类型.
- cout << s[] << endl;
自增自减符 ++, --
后缀法加了一个参数,有点意思。
From: https://www.runoob.com/cplusplus/increment-decrement-operators-overloading.html
- #include <iostream>
- using namespace std;
- class Time
- {
- private:
- int hours; // 0 到 23
- int minutes; // 0 到 59
- public:
- // 所需的构造函数
- Time(){
- hours = ;
- minutes = ;
- }
- Time(int h, int m){
- hours = h;
- minutes = m;
- }
- // 显示时间的方法
- void displayTime()
- {
- cout << "H: " << hours << " M:" << minutes <<endl;
- }
- // 重载前缀递增运算符( ++x )
- Time operator ++ ()
- {
- ++minutes; // 对象加 1
- if(minutes >= )
- {
- ++hours;
- minutes -= ;
- }
- return Time(hours, minutes);
- }
- // 重载后缀递增运算符( x++ )
- Time operator ++ (int)
- {
- // 保存原始值
- Time T(hours, minutes);
- // 对象加 1
- ++minutes;
- if(minutes >= )
- {
- ++hours;
- minutes -= ;
- }
- // 返回旧的原始值
- return T;
- }
- };
- -------------------------------------------------------------
- int main()
- {
- Time T1(, ), T2(,);
- ++T1; // T1 加 1
- T1.displayTime(); // 显示 T1
- ++T1; // T1 再加 1
- T1.displayTime(); // 显示 T1
- T2++; // T2 加 1
- T2.displayTime(); // 显示 T2
- T2++; // T2 再加 1
- T2.displayTime(); // 显示 T2
- return ;
- }
指针相关的,比较复杂,但不经常用到的运算符重载.
指针运算符 -> , *
/* 感觉用处不是很大 */
Ref: C++ 类成员访问运算符 -> 重载
- #include <iostream>
- #include <vector>
- using namespace std;
- // 假设一个实际的类
- class Obj {
- static int i, j;
- public:
- void f() const { cout << i++ << endl; }
- void g() const { cout << j++ << endl; }
- };
- // 静态成员定义
- int Obj::i = ;
- int Obj::j = ;
- // 为上面的类实现一个容器
- class ObjContainer {
- vector<Obj*> a;
- public:
- void add(Obj* obj)
- {
- a.push_back(obj); // 调用向量的标准方法
- }
- friend class SmartPointer;
- };
- // 实现智能指针,用于访问类 Obj 的成员
- class SmartPointer {
- ObjContainer oc;
- int index;
- public:
- SmartPointer(ObjContainer& objc)
- {
- oc = objc;
- index = ;
- }
- // 返回值表示列表结束
- bool operator++() // 前缀版本
- {
- if(index >= oc.a.size() - ) return false;
- if(oc.a[++index] == ) return false;
- return true;
- }
- bool operator++(int) // 后缀版本
- {
- return operator++();
- }
- // 重载运算符 ->
- Obj* operator->() const
- {
- if(!oc.a[index])
- {
- cout << "Zero value";
- return (Obj*);
- }
- return oc.a[index];
- }
- };
- int main() {
- const int sz = ;
- Obj o[sz];
- ObjContainer oc;
- for(int i = ; i < sz; i++)
- {
- oc.add(&o[i]);
- }
- SmartPointer sp(oc); // 创建一个迭代器
- do {
- sp->f(); // 智能指针调用
- sp->g();
- } while(sp++);
- return ;
- }
类成员访问运算符( -> )可以被重载,但它较为麻烦。它被定义用于为一个类赋予"指针"行为。运算符 -> 必须是一个成员函数。如果使用了 -> 运算符,返回类型必须是指针或者是类的对象。
运算符 -> 通常与指针引用运算符 * 结合使用,用于实现"智能指针"的功能。这些指针是行为与正常指针相似的对象,唯一不同的是,当您通过指针访问对象时,它们会执行其他的任务。比如,当指针销毁时,或者当指针指向另一个对象时,会自动删除对象。
-> 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的更多相关文章
- Operator overloading
By defining other special methods, you can specify the behavior of operators on user-defined types. ...
- [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)
operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...
- Lintcode208 Assignment Operator Overloading (C++ Only) solution 题解
[题目描述] Implement an assignment operator overloading method. Make sure that: The new data can be copi ...
- C# to IL 5 Operator Overloading(操作符重载)
Every operator overload that we use in C#, gets converted to a function call in IL. Theoverloaded &g ...
- 重载操作符 operator overloading 学习笔记
重载操作符,只是另外一种调用函数的方法和表现方式,在某些情况它可以让代码更简单易读.注意不要过度使用重载操作符,除非它让你的类更简单,让你的代码更易读. 1语法 如下: 其中友元,关键字不是必须的,但 ...
- 面向对象程序设计-C++ Operator Overloading & Type conversion (Static)【第十一次上课笔记】
本次上课继续讲解了 [ ] .-> 等运算符重载的具体例子 也讲解了C++单个参数的类的类型转换的案例 最后稍微提到了 static 的第三种作用:静态数据成员 具体详解我都已注释出来了,大家可 ...
- 面向对象程序设计-C++ Default constructor & Copy constructor& Destructor & Operator Overloading【第九次上课笔记】
先上笔记内容吧: 这次上课的内容有关 构造函数 析构函数 运算符重载 return * this 内容很细,大家好好回顾笔记再照应程序复习吧 :) #include <iostream> ...
- 8 Operator overloading
在类中,Groovy支持你使用标准的操作符.例如,如果你想使用a+b操作(a和b来自于Z类),那么你在Z类中,必须实现(implement)plus(Zname)方法.
- c++ operator
这篇博文是以前很久写的,贴在我的早期一个blog中,今天google一下,发现还真有不少人转载,可惜并不注明出处.那时觉得operator比较好玩.C++有时它的确是个耐玩的东东.operator它有 ...
随机推荐
- iOS开发UI高级手势识别器
####手势识别器 UIGestureRecognizer类 ·UITapGestureRecognizer(轻击) ·UIPinchGestureRecognizer(捏合) ·UIPanGestu ...
- .NET C#-- 利用BeginInvoke与EndInvoke完成异步委托方法并获取方法执行返回值示例
//定义委托 delegate string MyDelegate(string name); //定义委托调用函数 public string Hello(string name) { Thread ...
- USACO翻译:USACO 2013 NOV Silver三题
USACO 2013 NOV SILVER 一.题目概览 中文题目名称 未有的奶牛 拥挤的奶牛 弹簧牛 英文题目名称 nocow crowded pogocow 可执行文件名 nocow crowde ...
- final 评论ii
按照演讲顺序 1.约跑app 约跑app,从界面的单调,到最后的final发布,实现界面的友好性,有了很大的提高.约跑app,如果在约定地点可以显示出,所在位置,以及约定地址.就可以达 ...
- Silverlight 使用DataContractJsonSerializer序列化与反序列化 Json
环境说明:Silverlight 5.1,.Net Framework 4.0 1.添加引用System.ServiceModel.Web.dll. 因为 System.Runtime.Seria ...
- 最近在新公司的一些HTML学习
还是先把代码贴在这 后期再写感想 <!DOCTYPE html> <head> <meta http-equiv="x-ua-compatible" ...
- CSS选择器中类和ID选择器的区别
类和ID选择器的区别 学习了类选择器和ID选择器,我们会发现他们之间有很多的相似处,是不是两者可以通用呢?我们不要着急先来总结一下他们的相同点和不同点: 相同点:可以应用于任何元素不同点: 1.ID选 ...
- jQuery中设置form表单中action值与js有什么不同。。。。
jQuery中设置form表单中action值与js有什么不同.... HTML代码如下: <form action="" method="post" i ...
- PostgreSQL的.NET驱动程序Npgsql
Npgsql是PostgreSQL的一个.NET数据提供程序,它可以自由获取.它可以通过下列选项获得独立的下载,也可以安装PostgreSQL数据库程序时选择安装. 最新的_npgsql2 Npgsq ...
- 循序渐进做项目系列(4)迷你QQ篇(2)——视频聊天!(附源码)
一·效果展示 源码派送:MiniQQ1.1 文字聊天的实现参见:循序渐进做项目系列(3):迷你QQ篇(1)——实现客户端互相聊天 二·服务端设计 对于实现视频聊天而言,服务端最核心的工作就是要构造多媒 ...