一文搞懂C++中的运算符重载

Dulcea ·
更新时间:2024-11-10
· 1110 次阅读

目录

引入

一.运算符重载是什么

二.运算符重载的格式

三.部分运算符重载的实现

3.1 简单‘ + ’ ‘ - ’ ‘ * ’运算符重载

3.2 ++,- - 运算符

3.3 =运算符

3.4 <<,>>运算符

四.运算符重载注意事项

五.运算符重载的限制

六.MyString的简单实现

MyString.h

MyString.cpp

引入

对于基本类型的常量或变量进行运算时,我们可以使用 +、-、*、/ 等运算符,但是我们不可以使用运算符来进行对象之间的运算。

eg:对象之间的加法运算

class A { public: A(int i=0,int j=0,int k=0):m_i(i),m_j(j),m_k(k){} int geti() //接口 { return m_i; } int getj()//接口 { return m_j; } int getk()//接口 { return m_k; } void Add(A &b) { int i=m_i+b.m_j; int j=m_j+b.m_j; int k=m_k+b.m_k; cout<<i<<" "<<j<<" "<<k<<" "<<endl; } private: int m_i; int m_j; int m_k; }; void main() { A a(6,6,6); A b(7,7,7); a.Add(b); }

正如例子中所说:这里我们无法进行对象之间的加法,对于加法操作我们需要使用接口,然后定义add函数进行加法的操作,这样也就导致了代码十分复杂。

为了使得为了当前程序的可读性更好,简单明了。所以我们引入运算符重载这个概念。

利用 C++ 提供的“运算符重载”机制,赋予运算符新的功能,就能解决用+将两个复数对象相加这样的问题。

一.运算符重载是什么

运算符重载:就是对已有的运算符赋予多重含义,使同一运算符作用于不同类型的数据时产生不同的行为。

运算符重载的目的是使得 C++ 中的运算符也能够用来操作对象。

运算符重载的实质是编写以运算符作为名称的函数。

二.运算符重载的格式

返回值类型  operator  运算符(形参表)
{
    ....
}

这里对于返回值类型 大家可能会产生疑惑:什么是返回值类型,这里对返回值类型进行说明。

返回类型主要包括三类:

值返回

引用返回

指针返回

值返回与引用返回 – 基本数据类型

值返回:由运算符操作的表达式只能作为右值

引用返回: 由运算符所操作的表达式可作为左值

指针返回:有指针的相关操作

void main() { int i =10; int j =20; int k =0; i+j=k;// error 加号的表达式只可以做右值 //i+j有临时空间来存储表达式的值,但是没有确定的,不能把表达式的值放在i或者j空间 //不能作为左值的原因是 没有相应的内存空间 i有自己的空间 j有自己的空间 但是i+j没有 //右边要赋值给左边,那么左边必须要有确定的内存空间 k = i+j;//ok ++i = k;//i=30 /* ++i表达式的值 不管在什么时候都是i加过1之后的值,所以不用重新开辟临时空间存储表达式的值,用i的空间即可 ++i=k;就是把k的值放在i的内存单元 */ i++ = j;//error /* i++的j是i没有加过的值 但是最后i还是需要+1 所以此时i和i++不是同一个内存单元 所以需要重新开辟空间存储表达式的值,不可以这样使用 */ (i=j)=40;//=运算符可以作为左值 即可以引用返回 }

这里告诉大家如何快速判断是值返回还是引用返回:

判断是左值还是右值

如果对左值右值区分不是很清楚,可以参考这篇博客:

链接: c++左值,右值,将忘值

三.部分运算符重载的实现 3.1 简单‘ + ’ ‘ - ’ ‘ * ’运算符重载

对于简单‘ + ’ ‘ - ’ ‘ * ’运算符重载举例如下:

#include<stdio.h> #include<iostream> using namespace std; class A { public: A(int i=0):m_i(i){} A operator+(const A& t)//这里用const是为了本身值不改变 { cout << "A(+)" << endl; return m_i + t.m_i; } A operator-(const A& t)//这里用const是为了本身值不改变 { cout << "A(-)" << endl; return this->m_i-t.m_i; } A operator*(const A& t)//这里用const是为了本身值不改变 { cout << "A(*)" << endl; return this->m_i*t.m_i; } void print() { cout << m_i << endl; } private: int m_i; }; void main() { A a(10); A b(20); (a + b).print(); (a - b).print(); (a * b).print(); }

运算结果:

3.2 ++,- - 运算符

自增运算符++、自减运算符–都可以被重载,但是它们有前置、后置之分。

以++为例,假设 obj 是一个 CDemo 类的对象,++obj和obj++本应该是不一样的,前者的返回值应该是 obj 被修改后的值,而后者的返回值应该是 obj 被修改前的值。如果如下重载++运算符:

CDemo & CDemo::operator ++ () { //... return * this; }

不论obj++还是++obj,都等价于obj.operator++()无法体现出差别。

为了解决这个问题,C++ 规定,在重载++或- -时,允许写一个增加了无用 int 类型形参的版本,编译器处理++或–前置的表达式时,调用参数个数正常的重载函数;处理后置表达式时,调用多出一个参数的重载函数。

对于前置运算符:左值 引用返回

对于后置运算符:右值 值返回

举例如下:

#include <iostream> using namespace std; class CDemo { private: int n; public: CDemo(int i=0):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; } CDemo CDemo::operator++(int k ) { //后置 ++ CDemo tmp(*this); //记录修改前的对象 n++; return tmp; //返回修改前的对象 } CDemo & operator--(CDemo & d) {//前置-- d.n--; return d; } CDemo operator--(CDemo & d,int) {//后置-- CDemo tmp(d); d.n --; return tmp; } int main() { CDemo d(5); 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 0; } 3.3 =运算符

同类对象之间可以通过赋值运算符=互相赋值。如果没有经过重载,=的作用就是把左边的对象的每个成员变量都变得和右边的对象相等,即执行逐个字节拷贝的工作,这种拷贝叫作“浅拷贝”。

对于深拷贝浅拷贝可以参考这篇博客:

链接: c++拷贝构造函数

有的时候,两个对象相等,从实际应用的含义上来讲,指的并不应该是两个对象的每个字节都相同,而是有其他解释,这时就需要对=进行重载。

如果没有写=重载 呢么类会提供默认的=重载

对于=运算符举例如下:

A& operator=(const A& b) { cout << "=" << endl; m_i = b.m_i; return *this; } 3.4 <<,>>运算符

在 C++ 中,对于左移运算符<<可以和 cout 一起用于输出,因此也常被称为“输出运算符”。

实际上,对于<<来说,他本来并没有这样的功能,之所以能和 cout 一起使用,是因为被重载了。

cout 是 ostream 类的对象。ostream 类和 cout 都是在头文件 中声明的。ostream 类将<<重载为成员函数,而且重载了多次。为了使cout<<"Star War"能够成立,ostream 类需要将<<进行如下重载:

ostream & ostream::operator << (const char* s) { //输出s的代码 return * this; }

cin 是 istream 类的对象,是在头文件 中声明的。istream 类将>>重载为成员函数,因此 cin 才能和>>连用以输入数据。一般也将>>称为“流提取运算符”或者“输入运算符”

istream & operator>>( istream & is,Complex & c) { return is; } 四.运算符重载注意事项

1.可以重载成成员和友元两种形式

对象.operator运算符(第二个运算数)–成员形式

operator运算符(按照顺序写运算数)–友元形式

2.重载成成员形式,将第一个运算数省略(当成this)

重载成友元形式,参数不能省略 。

3.一般建议赋值重载为成员(如果第一个参数是本类对象,则重载魏本类的成员形式)

[]也建议重载为成员

<< >> 重载成友元,cout<<a.左操作数是cout的类对象,不可能是本类对象,只能重载为友元。

40运算符重载不可以改变优先级,结合性,操作数个数

五.运算符重载的限制

1.不可以臆造新的运算符

2.不可以改变原有运算符的优先级,语法等特点。

//不能将求模运算符(%)重载成使用一个操作数: int x; Time shiva; % x;    //无效的求模运算符 % shiva;  //无效的重载操作符

3.运算符重载不可以使用太多

4.重载运算符含义必须清楚,不能有二异性质

5.以下运算符不可以重载

6.下列运算符只能通过成员函数进行重载

=:赋值运算符

():函数调用运算符

[]:下标运算符

->:通过指针访问类成员的运算符

六.MyString的简单实现 MyString.h #ifndef MYSTRING_H #define MYSTRING_H #include<iostream> using namespace std; class mystring { char * _str; public: mystring(const char*str=nullptr); mystring(const mystring &another); mystring &operator=(const mystring&another); mystring operator+(const mystring&another); char& operator[](const int& i); bool operator==(const mystring&another); bool operator<(const mystring &another); bool operator>(const mystring &another); friend ostream &operator<<(ostream&out,mystring&str); int size(); ~mystring(); }; MyString.cpp #include "mystring.h" #include<string.h> int mystring::size(){ return strlen(this->_str); } mystring::mystring (const char* str){ if(str==nullptr) { _str=new char[1]; _str[0]='\0'; return; } _str=new char[strlen(str)+1]; strcpy(_str,str); } mystring::mystring(const mystring &another){ int lenth=strlen(another._str); _str=new char[lenth+1]; strcpy(_str,another._str); } mystring& mystring::operator=( const mystring&another){ if(*this==another)return *this; else { delete[] _str; int lenth=strlen(another._str); _str=new char[lenth+1]; strcpy(_str,another._str); return *this; } } mystring mystring:: operator+(const mystring&another){ mystring tmp; delete[] tmp._str; int lenth=strlen(_str)+strlen(another._str); tmp._str=new char[lenth+1]; memset(tmp._str,0,lenth); strcat(tmp._str,_str); strcat(tmp._str,another._str); return tmp; } char& mystring:: operator[](const int& i){ return _str[i]; } bool mystring:: operator==(const mystring&another){ if( strcmp(_str,another._str)==0) return true; else return false; } bool mystring:: operator<(const mystring &another){ if( strcmp(_str,another._str)<0) return true; else return false; } bool mystring:: operator>(const mystring &another){ if( strcmp(_str,another._str)>0) return true; else return false; } ostream & operator<<(ostream&out,mystring&str){ for(int i=0;i<strlen(str._str);++i) out<<str._str[i]; return out; } mystring:: ~mystring(){ delete[]_str; }

测试函数:

#include<iostream> #include<mystring.h> #include<string> using namespace std; int main(){ mystring test1("hello"); cout<<test1<<endl; cout<<test1[0]<<endl; mystring test2("world"); cout<<test2<<endl; mystring test3=test1+test2; cout<<test3<<endl; if(test1>test2) cout<<test1<<" > "<<test2<<endl; else if(test1==test2) cout<<test1<<" = "<<test2<<endl; else cout<<test1<<" < "<<test2<<endl; return 1; }

结果:

以上就是一文搞懂C++中的运算符重载的详细内容,更多关于C++运算符重载的资料请关注软件开发网其它相关文章!



c+ 重载 运算符 运算符重载 C++

需要 登录 后方可回复, 如果你还没有账号请 注册新账号