【c++】重载操作符
目录
- 输入和输出操作符
- 算术操作符和关系操作符
- 下标操作符
- 自加、自减操作符
- 成员访问操作符
1 输入和输出操作符
1.1 输出操作符
1.1.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
public:
A(const string &s = "", int v = ) : ss(s), val(v) {} //构造函数带默认参数
private:
int val;
string ss;
}; ostream& operator<<(ostream& out, const A& a)
{
out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
return out;
} int main()
{
A a("hello", );
cout << a << endl;
A b;
cout << b << endl;
}
结果
1.1.2 说明
1)IO操作必须为非成员函数
原因:I/O操作的接口返回的是ostream&对象(只有返回左值,这样才可以连续的输出,例如cout << a << b)。自定义的输出操作符应该与其相似。如果将其定义为成员函数(有个首默认参数this,即指向自己的指针),左操作数只能是该类型的对象,则没法办到。例如:Sales_item; item << cout; 与常规定义相反,因此只能为非成员函数。
2)因为要访问指定类的私有成员,所以在该类中声明输出操作符为友员函数。
3)第一个形参必须为引用。因为I/O对象不可以复制。同理返回值必须为一个引用。
4)第一个形参不可以为const,因为写入到流会改变其值。
5)第二个为引用,这样可以避免复制。参数可以为const,可以接收const对象和非const对象;否则,如果为非const,则只能接收非coust对象。一般为const,毕竟只是输出而已,不改变对象。
1.2 输入操作符
1.2.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
friend istream& operator>>(istream& in, A& a);
public:
A(const string &s = "", int v = ) : ss(s), val(v) {}
private:
int val;
string ss;
}; ostream& operator<<(ostream& out, const A& a)
{
out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
return out;
}
istream& operator>>(istream& in, A& a)
{
in >> a.ss >> a.val;
if(in)
{
cout << "Input right" << endl;
}
else
{
cout << "in.fail:" << in.fail() << endl;
cout << "input wrong!" << endl;
}
return in;
} int main()
{
A a("hello", );
cout << a << endl;
A b;
cin >> b;
cout << b << endl;
}
结果
1.2.2 说明
1)输入与输出操作符的重要区别:输入操作符必须处理错误和文件结束的可能性。
2)输入如果有多个值的话,如果一个数错了,整个输入对象就错了(False),从示例中可以看出,前边赋值正确的已经生效了,后边的用了默认值,可以这样设计:如果输入错误,将整个对象复位,恢复到最初的状态,例:
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
friend istream& operator>>(istream& in, A& a);
public:
A(const string &s = "", int v = ) : ss(s), val(v) {}
A(const A& a)
{
ss = a.ss;
val = a.val;
} A& operator=(const A& a)
{
if(this != &a)
{
ss = a.ss;
val = a.val;
return *this;
}
}
private:
int val;
string ss;
}; ostream& operator<<(ostream& out, const A& a)
{
out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
return out;
}
istream& operator>>(istream& in, A& a)
{
in >> a.ss >> a.val;
if(in)
{
cout << "Input right" << endl;
}
else
{
cout << "in.fail:" << in.fail() << endl;
cout << "input wrong!" << endl;
a = A();
}
return in;
} int main()
{
A a("hello", );
cout << a << endl;
A b;
b = a;
cin >> b;
cout << b << endl;
}
2 算术操作符和关系操作符
2.1 相等操作符
2.1.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend bool operator==(const A& a, const A& b);
friend bool operator!=(const A& a, const A& b);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
private:
string ss;
int val;
}; bool operator==(const A& a, const A& b)
{
return a.ss == b.ss && a.val == b.val;
} bool operator!=(const A& a, const A& b)
{
return !(a == b);
} int main()
{
A a("hello", );
A b("hello", );
A c("hello", );
cout << "a == b?:" << (a == b) << endl;
cout << "a != b?:" << (a != b) << endl;
cout << "b == c?:" << (b == c) << endl;
cout << "b != c?:" << (b != c) << endl;
}
结果
2.1.2说明
1)定义了类的==,对应的应该定义!=
2.2 关系操作符
2.2.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend bool operator<(const A& a, const A& b);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
private:
string ss;
int val;
}; bool operator<(const A& a, const A& b)
{
return (a.val < b.val);
} int main()
{
A a("hello", );
A b("he", );
cout << "a < b?:" << (a < b) << endl;
}
结果
2.2.2 说明
1)定义了相等操作符,一般也定义关系操作符
2)关系操作符要根据具体的含义定义
2.3 赋值操作符
2.3.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
A& operator=(const A& a);
private:
string ss;
int val;
}; ostream& operator<<(ostream &out, const A& a)
{
out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
} A& A::operator=(const A& a)
{
if(this != &a)
{
ss = a.ss;
val = a.val;
}
return *this;
} int main()
{
A a("hello", );
A b("he", );
cout << b << endl;
b = a;
cout << b << endl;
}
2.3.2 说明
1) 复制操作符完成对同类对象的赋值,参数一般为对类类型的const引用。
2)如果没有,编译器会自动合成一个,类的赋值操作符一定为类的成员变量,以便编译器是否需要自己合成一个。
3)返回值必须为*this的引用,这样就不需要创建和撤销结果的临时副本。同理的有复合赋值操作符,例如
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
A& operator+=(const A &);
private:
string ss;
int val;
}; ostream& operator<<(ostream &out, const A& a)
{
out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
} A& A::operator+=(const A& a)
{
val += a.val;
return *this;
} int main()
{
A a("hello", );
A b("he", );
a += b;
cout << a << endl;
}
结果
2.4 加法操作符
2.4.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
friend A operator+(const A &a ,const A &b);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
A(const A&);
A& operator+=(const A &);
private:
string ss;
int val;
}; A::A(const A& a)
{
ss = a.ss;
val = a.val;
} ostream& operator<<(ostream &out, const A& a)
{
out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
} A operator+(const A &a ,const A &b)
{
A tmp(a);
tmp += b;
return tmp;
} A& A::operator+=(const A& a)
{
val += a.val;
return *this;
} int main()
{
A a("hello", );
A b("he", );
a += b;
cout << a + b << endl;
}
2.4.2 说明
1) 根据复合操作符(如+=)实现算术操作符(如+),比其他方式更有效
3 下标操作符
3.1.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
char& operator[](const size_t);
const& char operator[](const size_t) const;
private:
string ss;
int val;
}; ostream& operator<<(ostream& out, const A& a)
{
out << "a.val:" << a.val << " " << "a.ss:" << a.ss;
return out;
} char& A::operator[](const size_t index)
{
return ss[index];
} const char& A::operator[](const size_t index) const
{
return ss[index];
} int main()
{
A a("hello", );
cout << a[] << endl;
}
结果
e
3.1.2 说明
1) 下标操作必须为函数成员,因为传递一个参数,还需要另一个指向自己的指针参数,正好函数成员的this可以胜任。
2) 类定义下标时,一般定义两个版本:一个为非const成员,并返回非const引用; 另一个为const成员,并返回const引用。这样应用与const对象时,返回值应为const引用,不能用作赋值的目标。
4 自加、自减操作符
4.1 前置自加、自减操作符
4.1.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
A& operator++();
A& operator--();
private:
string ss;
int val;
}; ostream& operator<<(ostream& out, const A& a)
{
out << "a.val:" << a.val << " " << "a.ss:" << a.ss;
return out;
} A& A::operator++()
{
++val;
return *this;
} A& A::operator--()
{
--val;
return *this;
} int main()
{
A a("hello", );
cout << a << endl;
++a;
cout << a << endl;
++a;
cout << a << endl;
--a;
cout << a << endl;
}
结果
4.2 后置自加、自减操作符
4.2.1 示例
#include <iostream>
#include <string>
using namespace std; class A
{
friend ostream& operator<<(ostream& out, const A& a);
public:
A(string s = "", int v = ) : ss(s), val(v) {}
A& operator++();
A& operator--();
A operator++(int);
A operator--(int);
private:
string ss;
int val;
}; ostream& operator<<(ostream& out, const A& a)
{
out << "a.val:" << a.val << " " << "a.ss:" << a.ss;
return out;
} A& A::operator++()
{
++val;
return *this;
} A& A::operator--()
{
--val;
return *this;
}
A A::operator++(int)
{
A tmp(*this);
++(*this);
return tmp;
} A A::operator--(int)
{
A tmp(*this);
--(*this);
return tmp;
} int main()
{
A a("hello", );
cout << a << endl;
++a;
cout << a << endl;
++a;
cout << a << endl;
cout << "hello" << endl;
cout << (a--) << endl;;
cout << a << endl;
}
4.2.2 说明
1)为了区分与前置自加、自减操作符的区别,后置需要接受一个而外的(无用的)的int型形参。使用后缀式操作符时,编译器提供0作为这个形参的实参,其唯一目的是为了区别前缀、后缀。
2)a++返回的是加之前的状态,因此,定义一个局部对象,保存(*this),最后返回这个局部变量的备份(注意不可以为引用,毕竟是局部的)。
5. 成员访问操作符
5.1.1 示例
#include <iostream>
#include <string>
using namespace std;
class B
{
public:
void print_B() { cout << "hello !!" << endl; }
};
class U_Ptr
{
friend class HasPtr;
B* ip;
size_t use;
U_Ptr(B *p) : ip(p), use() {}
~U_Ptr() { delete ip; }
}; class HasPtr
{
public:
HasPtr(B *p, int i) : ptr(new U_Ptr(p)), val(i) {}
HasPtr(const HasPtr &orig) : ptr(orig.ptr), val(orig.val) { ++ptr->use; }
HasPtr& operator=(const HasPtr &orig);
~HasPtr() { if(--ptr->use == ) delete ptr; }
B& operator*() { return *ptr->ip; }
B* operator->() { return ptr->ip; }
private:
U_Ptr *ptr;
int val;
}; HasPtr& HasPtr::operator=(const HasPtr &orig)
{
if(this != &orig)
{
ptr = orig.ptr;
val = orig.val;
++(ptr->use);
}
return *this;
} int main()
{
HasPtr hasptr1(new B, );
HasPtr hasptr2(hasptr1);
*hasptr1;
hasptr1->print_B();
}
结果
hello!!
5.1.2 说明
1) 箭头必须定义为成员函数, 解引用不要求定义为成员,但是可以作为成员。
2) 解引用和箭头操作常用在实现智能指针的类中。
【c++】重载操作符的更多相关文章
- 《精通C#》索引器与重载操作符(11.1-11.2)
1.索引器方法结构大致为<modifier><return type> this [argument list],它可以在接口中定义: 在为接口声明索引器的时候,记住声明只是表 ...
- C++ 重载操作符与转换
<C++ Primer 4th>读书笔记 重载操作符是具有特殊名称的函数:保留字 operator 后接需定义的操作符号. Sales_item operator+(const Sales ...
- 解释清楚c++的重载操作符【用自己的话,解释清楚】
C++中对于内置的变量及标准库中常见的类定义类常见的操作符含义,对于自定义的类也可以通过关键字operate 重载操作符的含义. C++中支持重载的目的 诚然操作符的重载可以通过使用函数实现同样的功能 ...
- 重载操作符 operator overloading 学习笔记
重载操作符,只是另外一种调用函数的方法和表现方式,在某些情况它可以让代码更简单易读.注意不要过度使用重载操作符,除非它让你的类更简单,让你的代码更易读. 1语法 如下: 其中友元,关键字不是必须的,但 ...
- [019]转--C++ operator关键字(重载操作符)
原博客:http://www.cnblogs.com/speedmancs/archive/2011/06/09/2076873.html operator是C++的关键字,它和运算符一起使用,表示一 ...
- VC6.0中重载操作符函数无法访问类的私有成员
整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...
- C++高精度运算类bign (重载操作符)
大数据操作,有例如以下问题: 计算:456789135612326542132123+14875231656511323132 456789135612326542132123*14875231656 ...
- C++ operator关键字(重载操作符)(转)
operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名. 这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算 ...
- C++中operator关键字(重载操作符)
operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名. 这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算 ...
- C++ Primer 学习笔记_60_重载操作符与转换 --赋值、下标、成员訪问操作符
重载操作符与转换 --赋值.下标.成员訪问操作符 一.赋值操作符 类赋值操作符接受类类型形參,通常该形參是对类类型的const引用,但也能够是类类型或对类类型的非const引用.假设未定义这个操作符, ...
随机推荐
- Arduino I2C + 气压传感器LPS25H
LPS25H是ST生产的MEMS数字气压传感器.主要特性有: 测量范围:260 ~ 1260 hPa绝对气压 分辨率:均方根1 Pa 工作电压:1.7 ~ 3.6 V 功耗:4μA(低分辨率模式)~2 ...
- INDEX--关于索引的琐碎
--=========================================================更新时的操作1>更新时有两种方式,一种是在原来的位置更新,另外一种是移除删除 ...
- MongoDB集群方案介绍
MongoDB集群方案介绍 一.什么是mongodb集群? 是指由多台mongodb服务器组成的服务器集群,称之为mongodb集群. 二.mongodb集群搭建的方式: 1.Replica Set ...
- 在红帽RHEL7.0里配置网卡的四种方法
第一种方法 :采用vim编辑器来配置: 1. 如下图的步骤所示: 2. 输入这个命令后进行配置成下方图片里的内容: 3. 然后退出vim 编辑器,然后重新启动一下网络服务配置: 4.这些配置完后 ...
- “全栈2019”Java第六十六章:抽象类与接口详细对比
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- centos7中使用Rsync和inotify同步文件
一. 环境说明 由于web服务器所提供的网站数据需要保持一致,但当服务器越来越多时,这些主机之间同步网站数据会很麻烦. 解决方案是在后端建立一个数据发布服务器,该服务器作为rsync客户端,通过ino ...
- easyui页面上显示和PL/SQL编码问题
在页面上,只需要显示人们看的懂的文字就行,但是在数据库里面就不一定了,一般情况下,在数据库里面存字母,数字等除了汉字以外的字符,存汉字有个问题,就是有时候不同oracle数据库的客户端会出现乱码问题: ...
- 浅谈Android选项卡(二)
前面简单介绍了选项卡,下面以及后面的几篇文章介绍下Android选项卡的几种简单实现方法. http://blog.csdn.net/xia215266092/article/details/9613 ...
- linux上的常用的进程与内存优化命令
进程 ps命令 f 以树状结构显示 u 显示详细信息 a 显示所有进程 -A 显示所有进程 -u 用户名 是显示该用户下的进程 -l 更多进程详细信息 例子1. 以树状结构显示root用户下进程的详细 ...
- 海思hi35xx 开发学习(2):系统控制
应用程序启动 MPP 业务前,必须完成 MPP 系统初始化工作.同理,应用程序退出MPP 业务后,也要完成 MPP 系统去初始化工作,释放资源. 视频缓存池 一组大小相同.物理地址连续的缓存块组成一个 ...