新标准C++程序设计读书笔记_运算符重载
形式
返回值类型 operator 运算符(形参表)
{
……
}
运算符重载
(1)运算符重载的实质是函数重载
(2)可以重载为普通函数,也可以重载为成员函数
class Complex
{
public:
double real,imag;
Complex( double r = 0.0, double i= 0.0 ):real(r),imag(i) { }
Complex operator-(const Complex & c);
}; Complex operator+( const Complex & a, const Complex & b)
{
return Complex( a.real + b.real, a.imag + b.imag); //返回一个临时对象
} Complex Complex::operator-(const Complex & c)
{
return Complex(real - c.real, imag - c.imag); //返回一个临时对象
} int main()
{
Complex a(,),b(,),c; //等价于c=operator+(a,b);
c = a + b;
cout << c.real << "," << c.imag << endl; //a-b等价于a.operator-(b)
cout << (a - b).real << "," << (a - b).imag << endl;
return ;
}
(3)把含运算符的表达式转换成对运算符函数的调用
(4)把运算符的操作数转换成运算符函数的参数
(5)运算符被多次重载时,根据实参的类型决定调用哪个运算符函数
(6)重载为成员函数时, 参数个数为运算符目数减一;重载为普通函数时, 参数个数为运算符目数
赋值运算符 ‘ =’重载
赋值运算符“ =”只能重载为成员函数
#include <iostream> using namespace std; class String
{
private:
char * str;
public:
String ():str(new char[]) { str[] = ;}
const char * c_str() { return str; };
String & operator = (const char * s);
String::~String( ) { delete [] str; }
}; String & String::operator = (const char * s)
{
//重载“=”以使得 obj = “hello”能够成立
delete [] str;
str = new char[strlen(s)+];
strcpy( str, s);
return * this;
} int main()
{
String s;
s = "Good Luck," ; //等价于 s.operator=("Good Luck,");
cout << s.c_str() << endl; /* 这条语句要是不注释掉就会出错,因为这是一个初始化语句而并不是赋值语句 */
// String s2 = "hello!"; s = "Shenzhou 8!"; //等价于 s.operator=("Shenzhou 8!");
cout << s.c_str() << endl;
return ;
}
浅拷贝和深拷贝
考察下面的代码
String S1, S2;
S1 = “this”;
S2 = “that”;
S1 = S2;
如果还用上面的运算符重载,那就会出现问题
(1)如不定义自己的赋值运算符,那么S1=S2实际上导致 S1.str和 S2.str指向同一地方。
(2)如果S1对象消亡,析构函数将释放S1.str指向的空间,再访问S2的时候就好玩儿了。
(3)另外,如果执行 S1 = "other";会导致S2.str指向的地方被delete
因此,要做如下修改:
String & operator = (const String & s)
{
if( this == & s)
return * this; delete [] str;
str = new char[strlen(s.str)+];
strcpy( str,s.str);
return * this;
}
ps:详细完成一个完整的String类,后续再补充
运算符重载为友元函数
一般情况下,将运算符重载为类的成员函数,是较好的选择。但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元。
class Complex
{
double real,imag;
public:
Complex( double r, double i):real(r),imag(i){ };
Complex operator+( double r );
}; Complex Complex::operator+( double r )
{
//能解释 c+5
return Complex(real + r,imag);
}
上面的类中重载的加号有局限性
Complex c ;
c = c + 5; //有定义,相当于 c = c.operator +(5);
但是:
c = 5 + c; //编译出错
为了使得上述的表达式能成立,需要将 + 重载为普通函数。但是普通函数又不能访问私有成员,所以,需要将运算符 + 重载为友元。
class Complex
{
double real,imag;
public:
Complex( double r, double i):real(r),imag(i){ };
Complex operator+( double r );
friend Complex operator + (double r,const Complex & c);
}; Complex Complex::operator+( double r )
{
//能解释 c+5
return Complex(real + r,imag);
} Complex operator+ (double r,const Complex & c)
{
//能解释 5+c
return Complex( c.real + r, c.imag);
}
设计一个变长数组类
想要达到下面目的
int main()
{
CArray a; //开始里的数组是空的
/*
要用动态分配的内存来存放数组元素,需要一个指针成员变量
*/
for( int i = ;i < ;++i)
a.push_back(i); CArray a2,a3;
/*
要重载“=”
*/
a2 = a;
for( int i = ; i < a.length(); ++i )
/*
要重载“[ ]”
*/
cout << a2[i] << " " ; a2 = a3; //a2是空的
for( int i = ; i < a2.length(); ++i ) //a2.length()返回0
cout << a2[i] << " ";
cout << endl; a[] = ;
/*
要自己写复制构造函数
*/
CArray a4(a);
for( int i = ; i < a4.length(); ++i )
cout << a4[i] << " "; return ;
}
类的设计如下:
class CArray {
int size; //数组元素的个数
int *ptr; //指向动态分配的数组
public:
CArray(int s = ); //s代表数组元素的个数
CArray(CArray & a);
~CArray();
void push_back(int v); //用于在数组尾部添加一个元素v
CArray & operator=( const CArray & a);
//用于数组对象间的赋值
int length() { return size; } //返回数组元素个数
int & CArray::operator[](int i) //返回值为 int 不行!不支持 a[i] = 4
{
//用以支持根据下标访问数组元素,
// 如n = a[i] 和a[i] = 4; 这样的语句
return ptr[i];
}
}; CArray::CArray(int s):size(s)
{
if( s == )
ptr = NULL;
else
ptr = new int[s];
} CArray::CArray(CArray & a)
{
if( !a.ptr) {
ptr = NULL;
size = ;
return;
}
ptr = new int[a.size];
memcpy( ptr, a.ptr, sizeof(int ) * a.size);
size = a.size;
} CArray::~CArray()
{
if( ptr) delete [] ptr;
} CArray & CArray::operator=( const CArray & a)
{
//赋值号的作用是使“=”左边对象里存放的数组,大小和内容都和右边的对象一样
if( ptr == a.ptr) //防止a=a这样的赋值导致出错
return * this; if( a.ptr == NULL) { //如果a里面的数组是空的
if( ptr )
delete [] ptr;
ptr = NULL;
size = ;
return * this;
} if( size < a.size) { //如果原有空间够大,就不用分配新的空间
if(ptr)
delete [] ptr;
ptr = new int[a.size];
} memcpy( ptr, a.ptr, sizeof(int) * a.size);
size = a.size;
return * this;
} void CArray::push_back(int v)
{
//在数组尾部添加一个元素
if( ptr) {
int * tmpPtr = new int[size + ]; //重新分配空间
memcpy(tmpPtr, ptr, sizeof(int) * size); //拷贝原数组内容
delete [] ptr;
ptr = tmpPtr;
}
else //数组本来是空的
ptr = new int[]; ptr[size++] = v; //加入新的数组元素
}
流运算符的重载
假定c是Complex复数类的对象,现在希望写“ cout << c;”,就能以“ a+bi”的形式输出c的值,写“ cin>>c;”,就能从键盘接受“ a+bi”形式的输入,并且使得c.real = a,c.imag = b。
class Complex
{
double real,imag;
public:
Complex( double r=, double i=):real(r),imag(i){ };
friend ostream & operator<<( ostream & os, const Complex & c);
friend istream & operator>>( istream & is,Complex & c);
}; ostream & operator<<( ostream & os,const Complex & c)
{
os << c.real << "+" << c.imag << "i"; //以"a+bi"的形式输出
return os;
} istream & operator>>( istream & is,Complex & c)
{
string s;
is >> s; //将"a+bi"作为字符串读入, “a+bi” 中间不能有空格
int pos = s.find("+", );
string sTmp = s.substr(, pos); //分离出代表实部的字符串
c.real = atof(sTmp.c_str()); //atof库函数能将const char*指针指向的内容转换成 float
sTmp = s.substr(pos+, s.length()-pos-); //分离出代表虚部的字符串
c.imag = atof(sTmp.c_str());
return is;
}
类型转换运算符
类型强制转换运算符被重载时不能写返回值类型,实际上其返回值类型就是该类型强制转换运算符代表的类型
#include <iostream>
using namespace std;
class Complex
{
double real,imag;
public:
Complex(double r=,double i=):real(r),imag(i) { };
//重载强制类型转换运算符 double
operator double () { return real; } }; int main()
{
Complex c(1.2,3.4);
cout << (double)c << endl; //输出 1.2
double n = + c; //等价于 double n=2+c.operator double()
cout << n; //输出 3.2
}
自增,自减运算符的重载
1、前置运算符作为一元运算符重载
(1)重载为成员函数:
T & operator++();
T & operator--();
(2)重载为全局函数:
T1 & operator++(T2);
T1 & operator—(T2);
2、后置运算符作为二元运算符重载,多写一个没用的参数
(1)重载为成员函数:
T operator++(int);
T operator--(int);
(2)重载为全局函数:
T1 operator++(T2,int );
T1 operator—( T2,int);
class CDemo
{
private:
int n;
public:
CDemo(int i=):n(i) { }
CDemo & operator++(); //用于前置形式
CDemo operator++( int ); //用于后置形式
operator int ( ) { return n; }
friend CDemo & operator--(CDemo & );
friend CDemo operator--(CDemo & ,int);
}; CDemo & CDemo::operator++()
{
//前置 ++
n++;
return * this;
} // ++s即为: s.operator++(); CDemo CDemo::operator++( int k )
{
//后置 ++
CDemo tmp(* this); //记录修改前的对象
n++;
return tmp; //返回修改前的对象
} // s++即为: s.operator++(0); CDemo & operator--(CDemo & d)
{
//前置--
d.n--;
return d;
} //--s即为: operator--(s); CDemo operator--(CDemo & d,int)
{
//后置--
CDemo tmp(d);
d.n--;
return tmp;
} //s--即为: operator--(s, 0); int main()
{
CDemo d();
cout << (d++ ) << ","; //等价于 d.operator++(0);
cout << d << ",";
cout << (++d) << ","; //等价于 d.operator++();
cout << d << endl;
cout << (d-- ) << ","; //等价于 operator--(d,0);
cout << d << ",";
cout << (--d) << ","; //等价于 operator--(d);
cout << d << endl;
return ;
}
运算符重载的注意事项
(1)C++不允许定义新的运算符 ;
(2)重载后运算符的含义应该符合日常习惯;
complex_a + complex_b
word_a > word_b
date_b = date_a + n
(3)运算符重载不改变运算符的优先级;
(4)以下运算符不能被重载:“.” 、“.*” 、“::” 、“?:” 、 sizeof;
(5)重载运算符()、 []、 ->或者赋值运算符=时,运算符重载函数必须声明为类的成员函数。
新标准C++程序设计读书笔记_运算符重载的更多相关文章
- 新标准C++程序设计读书笔记_类和对象
面向对象的程序设计方法 抽象:将某类客观事物共同特点(属性)归纳出来,形成一个数据结构(可以用多个变量描述事物的属性):将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构 ...
- 新标准C++程序设计读书笔记_继承和多态
简单继承的例子: #include <iostream> #include <string> using namespace std; class CStudent { pri ...
- 正确处理类的复合关系------新标准c++程序设计
假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...
- string类------新标准c++程序设计
定义: string类是STL中basic_string模板实例化得到的模板类.其定义如下: typedef basic_string<char>string; 构造函数: string类 ...
- 指针和动态分配内存 (不定长度数组)------新标准c++程序设计
背景: 数组的长度是定义好的,在整个程序中固定不变.c++不允许定义元素个数不确定的数组.例如: int n; int a[n]; //这种定义是不允许的 但是在实际编程中,往往会出现要处理的数据数量 ...
- 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计
类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...
- 多态实现的原理------新标准c++程序设计
“多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定.例子: #include<iostream> using namespac ...
- 多态的作用-游戏编程展示------新标准c++程序设计
游戏软件的开发最能体现面向对象设计方法的优势.游戏中的人物.道具.建筑物.场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程.每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方 ...
- 类与类之间的两种关系------新标准c++程序设计
在c++中,类和类之间有两种基本关系:复合关系和继承关系. 复合关系也称为“has a”关系或“有”的关系,表现为封闭类,即一个类以另一个类的对象作为成员变量. 继承关系也称为“is a”关系或“是” ...
随机推荐
- NPD南京炮苑电子技术研究所----NPD治疗仪
NPD南京炮苑电子技术研究所有限公司: http://www.npd365.com/ 研发药物离子导入和中医定向透药技术. 南京炮苑玉古康2号NPD系列专用中医定向透药治疗仪腰颈椎疼痛贴 N ...
- Mac系统使用VS Code编译Bootstrap 4
环境: macOS 10.13.6 node.js 8.11.3 sass 1.10.3 bootstrap 4.1.3 vs code 1.25.1 Bootstrap3为我们提供了在线编译工具,可 ...
- Razor语法(三)
1.定义变量 定义变量或声明常量必须在代码体内,代码体以'@{'开头,以'}'结束,其中定义变量以'var'进行声明.代码体内每行以';'做为结束标识. @{ var i = 10; ...
- php中自定义事件---事件驱动
PHP中自定义事件驱动,处理机制. 原文:https://www.cnblogs.com/mafeifan/p/4322271.html ------------------------------- ...
- 用dd命令复制磁盘分区
用dd命令复制磁盘分区 首先是复制 复制前对写入的分区执行umount操作 sudo dd if=/dev/sda1 of=/dev/sda2 可以在另外一个终端输入这句,然后在原来的dd终端看到进度 ...
- JMeter 十六:加密处理
假设采用MD5进行加密 JMeter 内置的没有MD5加密方法.网上有说采用__MD5函数的,但是我在 Jmeter 2.13 以及 Jmeter 3.2 版本上都没有找到这个函数,官方文档也没有看到 ...
- 《深入浅出pig系列之中的一个》pig-0.12.0-cdh5.1.2的安装与执行
这里使用的版本号是cdh发行的pig-0.12.0-cdh5.1.2 下载地址点这里 1.Pig简单介绍: Pig是yahoo捐献给apache的一个项目.它是SQL-like语言.是在MapRedu ...
- 算法笔记_057:蓝桥杯练习 最大的算式 (Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大.因为乘号和加号一共就 ...
- Sketch 介绍
Sketch 插件大集合 -- Using Sketch Like A BOSS 这几天发现了一个叫做 Sketch Toolbox 的 Mac 应用,简直是下载和安装 Sketch 插件 ...
- Spring2.5学习4.2_Proxy实现动态代理(目标类实现随意接口)
静态代理的缺点是在代理类中绑定了固定的接口,不利于扩展,动态代理则不然,通过动态代理能够对不论什么实现某一接口的类进行功能性增强. 在java中动态代理由InvocationHander来实现. He ...