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


==

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

声明关键字 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++操作符重载形式——成员函数or友元函数

一般来说,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的更多相关文章

  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. myeclipse中导入js报如下错误Syntax error on token "Invalid Regular Expression Options", no accurate correc

    今天在使用bootstrap的时候引入的js文件出现错误Syntax error on token "Invalid Regular Expression Options", no ...

  2. 关于bootstrap和响应式布局

    bootstrap导入 首先需要安装好插件 然后就是在代码器写导入代码 代码如下 <html lang="zh-CN"> <head> <meta c ...

  3. Concurrency并发性

    今天看了有关性能的文章,性能也是客户所看重的. 文章推荐看了软件编程并发性. 就按书上敲了网址看:http://www.gotw.ca/publications/concurrency-ddj.htm ...

  4. 一步步学习javascript基础篇(3):Object、Function等引用类型

    我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂 ...

  5. ES7之Decorators实现AOP示例

    在上篇博文CoffeeScript实现Python装潢器中,笔者利用CoffeeScript支持的高阶函数,以及方法调用可省略括符的特性,实现了一个类似Python装潢器的日志Demo.这只是一种伪实 ...

  6. Redis高可用分布式内部交流(九)

    这是上月在公司内部的一次分享,现把PPT及交流内容整理成博客. 阅读目录: 高可用 数据同步 分布式 分布式集群时代 总结 高可用 高可用(High Availability),是当一台服务器停止服务 ...

  7. 利用C#自带组件强壮程序日志

    在项目正式上线后,如果出现错误,异常,崩溃等情况 我们往往第一想到的事就是查看日志 所以日志对于一个系统的维护是非常重要的 声明 正文中的代码只是一个栗子,一个非常简单的栗子,只是说明这个框架是怎么工 ...

  8. EF:自定义Oracle的映射类型

    oracle在DB First模式下,int类型的字段会自动映射为decmial类型的属性. 我们可以通过自定义类型映射进行“纠整”. 在app.config 自定义映射规则: <oracle. ...

  9. C语言 · 回文数 · 基础练习

    问题描述 1221是一个非常特殊的数,它从左边读和从右边读是一样的,编程求所有这样的四位十进制数. 输出格式 按从小到大的顺序输出满足条件的四位十进制数.   代码如下: 注意:这里要提醒一下读者:蓝 ...

  10. linux java so 历险

    一开始 -bash-4.1# java -cp "/usr/linkapp/bin/tomcat-master/webapps/ROOT/WEB-INF/lib/*":" ...