C++之运算符重载(1)

  在前一节中曾提到过,C++中运行时的多态性主要是通过虚函数来实现的,而编译时的多态性是由函数重载和运算符重载来实现的。这一系列我将主要讲解C++中有关运算符重载方面的内容。在每一个系列讲解之前,都会有它的一些基础知识需要我们去理解。而运算符重载的基础就是运算符重载函数。所以今天主要讲的是运算符重载函数。

  1.运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用域不同类型的数据导致不同行为的发生。比如

int i;
int i1=10,i2=10;
i=i1+i2;
std::cout<<"i1+i2="<<i<<std::endl;

double d;
double d1=20,d2=20;
d=d1+d2;
std::cout<<"d1+d2="<<d<<std::endl;

在这个程序里"+"既完成两个整形数的加法运算,又完成了双精度型的加法运算。为什么同一个运算符"+"可以用于完成不同类型的数据的加法运算?这是因为C++针对预定义基本数据类型已经对"+"运算符做了适当的重载。在编译程序编译不同类型数据的加法表达式时,会自动调用相应类型的加法运算符重载函数。但是C++中所提供的预定义的基本数据类型毕竟是有限的,在解决一些实际的问题时,往往需要用户自定义数据类型。比如高中数学里所提到的复数:

class Complex //复数类
{
public:
double real;//实数
double imag;//虚数
        Complex(double real=0,double imag=0)
        {
this->real=real;
this->imag=imag;
        }
}

假如我们建立两个复数,并用"+"运算符让它们直接相加:

1 Complex com1(10,10),com2(20,20),sum;2 sum=com1+com2;

那么会提示没有与这些操作数匹配的 "+" 运算符的错误。这是因为Complex类类型不是预定义类型,系统没用对该类型的数据进行加法运算符函数的重载。C++就为运算符重载提供了一种方法,即运算符重载函数。其函数名字规定为operator后紧跟重载运算符。比如:operator+(),operator*()等。现在我们给上述程序声明一个加法运算符的重载函数用于完成复数的加法运算:

#include "stdafx.h"
#include <iostream>

class Complex //复数类
{
public:
double real;//实数
double imag;//虚数
        Complex(double real=0,double imag=0)
        {
this->real=real;
this->imag=imag;
        }
};

Complex operator+(Complex com1,Complex com2)//运算符重载函数
{
return Complex(com1.real+com2.real,com1.imag+com2.imag);
}

int main()
{
    Complex com1(10,10),com2(20,20),sum;
    sum=com1+com2;//或sum=operator+(com1,com2)

    std::cout<<"sum的实数部分为"<<sum.real<<std::endl;
    std::cout<<"sum的虚数部分为"<<sum.imag<<"i"<<std::endl;

return0;
}

结果:

在上述示例代码中,调用运算符重载函数时,也可以以operator+(com1,com2)的形式来调用,实际上com1+com2在程序解释时也是转化成前者一样的形式。但是直接用com1+com2的形式更加符合人的书写习惯。

  2.上述示例中的运算符重载函数是不属于任何的类,是全局的函数。因为在Complex类(复数类)中的数据成员是公有的性质,所以运算符重载函数可以访问。但如果定义为私有的呢,那该怎么办。其实,在实际的运算符重载函数声明当中,要不定义其为要操作类的成员函数或类的友元函数。

  (1)运算符重载函数作为类的友元函数的形式:

  class 类名

  {

    friend 返回类型 operator运算符(形参表);

  }

  类外定义格式:

  返回类型 operator运算符(参数表)

  {

    函数体

  }

友元函数重载双目运算符(有两个操作数,通常在运算符的左右两则),参数表中的个数为两个。若是重载单目运算符(只有一个操作数),则参数表中只有一参数。

i.友元函数重载双目运算符(+):

#include "stdafx.h"
#include <iostream>

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
        Complex(double real=0,double imag=0)
        {
this->real=real;
this->imag=imag;
        }
        friend Complex operator+(Complex com1,Complex com2);//友元函数重载双目运算符+
void showSum();
};

Complex operator+(Complex com1,Complex com2)//友元运算符重载函数
{
return Complex(com1.real+com2.real,com1.imag+com2.imag);
}

void Complex::showSum()
{
    std::cout<<real;
if(imag>0)
        std::cout<<"+";
if(imag!=0)
        std::cout<<imag<<"i"<<std::endl;
}

int main()
{
    Complex com1(10,10),com2(20,-20),sum;
    sum=com1+com2;//或sum=operator+(com1,com2)
    sum.showSum();//输出复数相加结果

return0;
}

结果:

ii.友元函数重载单目运算符(++):

#include "stdafx.h"
#include <iostream>

class Point//坐标类
{
private:
int x;
int y;
public:
    Point(int x,int y)
    {
this->x=x;
this->y=y;
    }
    friend voidoperator++(Point& point);//友元函数重载单目运算符++
void showPoint();
};

voidoperator++(Point& point)//友元运算符重载函数
{
++point.x;
++point.y;
}

void Point::showPoint()
{
    std::cout<<"("<<x<<","<<y<<")"<<std::endl;
}

int main()
{
    Point point(10,10);
++point;//或operator++(point)
    point.showPoint();//输出坐标值

return0;
}

结果:

运算符重载函数可以返回任何类型,甚至是void,但通常返回类型都与它所操作的类类型一样,这样可以使运算符使用在复杂的表达式中。比如把上述双目运算符重载函数示例代码中main()主函数里的com1+com2改为com1+com2+com2,那么结果又会不一样了。像赋值运算符=、下标运算符[]、函数调用运算符()等是不能被定义为友元运算符重载函数。同一个运算符可以定义多个运算符重载函数来进行不同的操作。

  (2)运算符重载函数作为类的成员函数的形式:

  class 类名

  {

    返回类型 operator 运算符(形参表);

  }

   类外定义格式:

  返回类型 类名:: operator 运算符(形参表)

  {

    函数体;

  }

对于成员函数重载运算符而言,双目运算符的参数表中仅有一个参数,而单目则无参数。同样的是重载,为什么和友元函数在参数的个数上会有所区别的。原因在于友元函数,没有this指针。

i.成员函数重载双目运算符(+):

#include "stdafx.h"
#include <iostream>

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
        Complex(double real=0,double imag=0)
        {
this->real=real;
this->imag=imag;
        }
        Complex operator+(Complex com1);//成员函数重载双目运算符+
void showSum();
};

Complex Complex::operator+(Complex com1)
{
return Complex(real+com1.real,imag+com1.imag);
}

void Complex::showSum()
{
    std::cout<<real;
if(imag>0)
        std::cout<<"+";
if(imag!=0)
        std::cout<<imag<<"i"<<std::endl;
}

int main()
{
    Complex com1(10,10),com2(20,-20),sum;
    sum=com1+com2;//或sum=com1.operator+(com2)
    sum.showSum();//输出复数相加结果
return0;
}

对于双目运算符而言,运算符重载函数的形参中仅为一个参数,它作为运算符的右操作数(如com2对象),而当前对象作为左操作数(如:上述中的com1对象),它是通过this指针隐含传递给成员运算符重载函数的。

ii.成员函数重载单目运算符(++):

#include "stdafx.h"
#include <iostream>

class Point//坐标类
{
private:
int x;
int y;
public:
    Point(int x,int y)
    {
this->x=x;
this->y=y;
    }
voidoperator++();//成员函数重载双目运算符++
void showPoint();
};

void Point::operator++()
{
++x;
++y;
}

void Point::showPoint()
{
    std::cout<<"("<<x<<","<<y<<")"<<std::endl;
}

int main()
{
    Point point(10,10);
++point;//或point.operator++()
    point.showPoint();//输出坐标值

return0;
}

对于单目运算符而言,当前对象作为运算符的操作数。

  在运算符重载运用时应该注意以下几个问题:(1)C++中只能对已有的C++运算符进行重载,不允许用户自己定义新的运算符;(2)C++中绝大部分的运算符可重载,除了成员访问运算符.,成员指针访问运算符.*,作用域运算符::,长度运算符sizeof以及条件运算符?:;(3)重载后不能改变运算符的操作对象(操作数)的个数。如:"+"是实现两个操作数的运算符,重载后仍然为双目运算符;(4)重载不能改变运算符原有的优先级;(5)重载不能改变运算符原有结合的特性。比如:z=x/y*a,执行时是先做左结合的运算x/y,重载后也是如此,不会变成先做右结合y*a;(6)运算符重载不能全部是C++中预定义的基本数据,这样做的目的是为了防止用户修改用于基本类型数据的运算符性质;(7)从上述的示例中可以看到双目运算符可以被重载为友元函数也可以重载为成员函数,但有一种情况,只能使用友元函数,是什么情况呢?我举个例子: 

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
        Complex(double real=0,double imag=0)
        {
this->real=real;
this->imag=imag;
        }
        Complex operator+(int x);
};

Complex Complex::operator+(int x)
{
return Complex(real+x,imag);
}

int main()
{
    Complex com1(5,10),total;
    total=com1+5;

return0;
}

如果我们把上述main()主函数实现部分里的total=com1+5改为total=5+com1;那么程序就会报错(没有与这些操作数匹配的 "+" 运算符),因为左操作数5不是该复数类的对象,不能调用相应的成员函数Complex operator+(int x),所以编译错误。但如果我们定义一下两个友元函数就能解决上述的问题:

  friend Complex operator+(Complex com1,int x);

  friend Complex operator+(int x,Complex com1);

  3.最后还是一样,我将用一个示例来总结一下今天所讲的内容(开发工具:vs2010): 

#include "stdafx.h"
#include <iostream>

class Complex //复数类
{
private://私有
double real;//实数
double imag;//虚数
public:
        Complex(double real=0,double imag=0)
        {
this->real=real;
this->imag=imag;
        }
        Complex operator+(Complex com1);//成员函数重载双目运算符+
//或friend Complex operator+(Complex com1,Complex com2);//友元函数重载双目运算符+
        friend Complex operator+(Complex com1,int x);//友元函数重载双目运算符+
//或Complex operator+(int x);
        friend Complex operator+(int x,Complex com1);//友元函数重载双目运算符+
void showSum();
};

Complex Complex::operator+(Complex com1)
{
return Complex(real+com1.real,imag+com1.imag);
}

Complex operator+(Complex com1,int x)//左操作数类型为复数,右操作数的类型为整数
{
return Complex(com1.real+x,com1.imag);
}

Complex operator+(int x,Complex com1)//左操作数类型为整数,右操作数的类型为复数
{
return Complex(x+com1.real,com1.imag);
}

void Complex::showSum()
{
    std::cout<<real;
if(imag>0)
        std::cout<<"+";
if(imag!=0)
        std::cout<<imag<<"i"<<std::endl;
}

class Point//坐标类
{
private:
int x;
int y;
public:
    Point(int x,int y)
    {
this->x=x;
this->y=y;
    }
    friend voidoperator++(Point& point);//友元函数重载单目运算符++
    Point operator++();//成员函数重载双目运算符++
void showPoint();
};

voidoperator++(Point& point)//友元运算符重载函数
{
++point.x;
++point.y;
}

Point Point::operator++()
{
++x;
++y;
return*this;//返回当前对象
}

void Point::showPoint()
{
    std::cout<<"("<<x<<","<<y<<")"<<std::endl;
}

int main()
{
//两个复数相加
    std::cout<<"两个复数相加:"<<std::endl;

    Complex com1(10,10),com2(20,-20),sum;
    sum=com1+com2;//或sum=com1.operator+(com2)
    std::cout<<"(10+10i)+(20-20i)=";
    sum.showSum();//输出复数相加结果

//三个复数相加
    std::cout<<"三个复数相加:"<<std::endl;

    sum=com1+com2+com2;
    std::cout<<"(10+10i)+(20-20i)+(20-20i)=";
    sum.showSum();

//整数和复数相加
    std::cout<<"整数和复数相加:"<<std::endl;

    Complex com3(5,10),total;
    total=com3+5;//或total=operator+(com1,5);
    std::cout<<"(5+10i)+5=";
    total.showSum();

    total=5+com3;//或total=operator+(5,com1);
//只能用友元函数来重载运算符
    std::cout<<"5+(5+10i)=";
    total.showSum();

//单目运算符++重载
    std::cout<<"单目运算符++重载:"<<std::endl;

//注意:下述实现部分不能只用一个++point会造成二义性
    Point point(10,10);
//调用友元函数
operator++(point);//或++point
    std::cout<<"调用友元函数:++(10,10)=";
    point.showPoint();//输出坐标值

//调用成员函数
    point=point.operator++();//或++point;
    std::cout<<"调用成员函数:++(10,10)=";
    point.showPoint();

return0;
}

结果:

C++之运算符重载(1),布布扣,bubuko.com

时间: 2024-12-26 12:30:56

C++之运算符重载(1)的相关文章

关于运算符重载

运算符重载需遵循以下原则: 1.除了类所属关系运算符".".成员指针运算符".*".作用域运算符"::".sizeof运算符.三目运算符"?:"之外,C++中所有的运算符都可以进行重载 2.重载运算符限制在C++已有的运算符范围内,不允许创建新的运算符 3.重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数的个数及语法结构 4.运算符重载不能改变运算符用于内置类型的对象的含义,只能用于自定义类型对象之间,

运算符重载

关键字:operator 相见:<高质量程序设计指南> P255 如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,有两个参数的运算符叫做二元运算符. 如果运算符被重载为类的成员函数,那么一元运算符没有参数(但是++和--运算符的后置版本除外),二元运算符只有右侧参数,因为对象自己成了左侧参数. 运算符重载的特殊性 如果重载为成员函数,则this对象发起对它的调用 如果重载为全局函数,则第一个参数发起对它的调用 禁止用户发明该语言运算符集合中不存在的运算符 除了函数调用运算符

C++ 运算符重载

C++中预定义的运算符的操作对象只能是基本数据类型,实际上,对于很多用户自定义类型,也需要有类似的运算操作.比如对象a和对象b, 那么 a+b 就需要用户自己定义它怎么相加,这时就用到了运算符重载. 运算符重载规则如下: ①. C++中的运算符除了少数几个之外,全部可以重载,而且只能重载C++中已有的运算符. ②. 重载之后运算符的优先级和结合性都不会改变. ③. 运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造.一般来说,重载的功能应当与原有功能相类似,不能改变原运算符的操作对

Kotlin中复合赋值(+=,-=,……)运算符重载

本篇建立在已经了解了kotlin中运算符重载的理念以及如何实现的基础上. 来我们首先写一个简单的类,然后重载运算符+,+=,-,-=这个几个运算符.代码如下: data class Point(var x: Int, var y: Int) { operator fun plus(point: Point): Point { return Point(this.x + point.x, this.y + point.y) } operator fun plusAssign(point: Poin

第十章 运算符重载

第十章 运算符重载 1.运算符重载的方法 (实质:函数重载) *一般格式: 函数类型名operator 运算符名称(参数表){函数体:} 2.运算符重载的规则 *不允许定义新的运算符 *允许重载的运算符 双目运算符 +(加法)  - (减法)  * (乘法) / (除法)   %(取模) 关系运算符 ==(等于) != (不等)  <   >   <=   >= 逻辑运算符 ||(或)   && (与)  !(非) 单目运算符 + (正)  -(负)   *(指针)

C++运算符重载的妙用

运算符重载(Operator overloading)是C++重要特性之中的一个,本文通过列举标准库中的运算符重载实例,展示运算符重载在C++里的妙用.详细包含重载operator<<,operator>>支持cin,cout输入输出.重载operator[],实现下标运算.重载operator+=实现元素追加:重载operator()实现函数调用.假设你对C++的运算符重载掌握的游刃有余.那就无需继续往下看了. 运算符重载带来的优点就是--让代码变得简洁.以下将展示几个标准库因使

网易云课堂_C++开发入门到精通_章节4:运算符重载

课时23运算符重载 运算符重载 重载赋值运算符 Person& Person::operator=(const Person& other) { //检查自赋值 if (this == &other) { return *this; } //释放原有的内存资源 delete[]m_data; int length = strlen(other.m_data); m_data = new char[length + 1]; strcpy(m_data, other.m_data);

关于c++的运算符重载那些事

搞c++有一段时间了,今天突然要重载一个运算符,发现自己有点忘了,遂查查资料做一下c++运算符重载的小总结. 一.何为运算符重载 运算符的重载是c++语言特有的,java什么的是没有运算符重载的,所以运算符重载在笔试面试中有可能成为c++的高频考点.运算符重载就是重新定义运算符的意义,如常用的+,-,×,÷都是可以重载的.运算符重载使用的是关键字operator,表现形式是:                                                            

C++:运算符重载函数之&quot;++&quot;、&quot;--&quot;、&quot;[ ]&quot;的应用

5.2.5 "++"和"--"的重载 对于前缀方式++ob,可以用运算符函数重载为: ob.operator++() //成员函数重载 或 operator++(X &ob) //友元函数重载,其中ob为类X的对象的引用 对于后缀方式++ob,可以用运算符函数重载为: ob.operator++(int) //成员函数重载 或 operator++(X &ob,int) //友元函数重载,其中ob为类X的对象的引用 调用时,参数int一般被传递给值0

C++:运算符重载函数之成员运算符重载函数

5.2.3 成员运算符重载函数 在C++中可以把运算符重载函数定义为某个类的成员函数,称之为成员运算符重载函数. 1. 定义成员运算符重载函数的语法形式 (1)在类的内部,定义成员运算符重载函数的格式如下: 函数类型 operator 运算符(形参表) {       函数体 } (2)成员运算符重载函数也可以在类中声明成员函数的原型,在类外定义. 在类的内部,声明成员运算符重载函数原型的格式如下: class X{      ...      函数类型 operator运算符(参数表); };