C++中的运算符重载详解

目录
  • 1、引例
  • 2、类中自动建立的函数
  • 3、重载赋值运算符解析
  • 总结

1、引例

class Complex
{
private:
    double Real,Image;
public:
    Complex():Real(0),Image(0)  {}
    Complex(double r, double i) : Real(r),Image(i) {}
    ~Complex()  {}
};

int main()
{
    Complex c1(1.2,2.3);
    Complex c2(45,56);

    Complex c3;
    c3 = c1.Add(c2);        

}

类非常简单,下面我们要讨论如何写一个Add函数,使得两个对象的属性相加,返回一个新的对象。

第一种:

Complex::Complex Add(const Complex &c)
{
    Complex co;
    co.Real = this->Real + c.Real;
    co.Image = this->Image + c.Image;
    return co;
}

问题1:如何写出最节省空间的Add函数?

第二种:

Complex::Complex Add(const Complex &c) const
{
    return Complex(c.Real + this->Real, c.Image + this.Image);
}

由于不需要改变调用对象的属性值,我们给this指针添加const 修饰。

分析过程如下:

问题2:为什么第一种方式不节省空间呢?

首先第一种的代码比较繁琐,并且在函数栈帧中又创建了一个对象(第3行)。并且函数类型是值传递类型(第6行),返回的是一个将亡值对象。那么整个Add函数空间会产生两个对象,造成空间的浪费。

第二中代码创建的是无名对象,减少了一个co对象的创建,并且将无名对象直接作为将亡值对象传递给main函数中的c3。

问题3:我们能否将Add函数改为引用类型,这样来减少将亡值对象的创建

Complex::Complex &Add(const Complex &c) const
{
    return Complex(c.Real + this->Real, c.Image + this.Image);
}

VS2019发现报错,不能返回引用对象:

我们进行分析:

问题4:我们能否将这个Add函数名改为 + 运算符?

//Complex::Complex Add(const Complex &c) const
Complex::Complex +(const Complex &c) const
{
	Complex co;
	co.Real = this->Real + c.Real;
	co.Image = this->Image + c.Image;
	return co;
}

int main()
{
    ...
    //c3 = c1.Add(c2);
    c3 = c1.+(c2);    //将原先Add的地方改变为加号。
    ...
}

这样使用,编译器又会报错,操作符不可作为一个有效的函数名来被使用

问题5:如何使 +预算符 作为函数名使用?

这就引出了今天的关键,函数运算符重载

在C++中,为了使操作符作为一个有效的函数名,我们在操作符前面添加一个operator

Complex operator+(const Complex &c) const
{
     return Complex(c.Real + this->Real,c.Image + this->Image);
}

int main()
{
     Complex c1(1.2,2.3);
     Complex c2(10,10);
     Complex c3;
     c3 = c1 + c2;

     //上面一行实际上是
     //c3 = c1.operator+ (c2);
     //c3 = operator+(&c1,c2);  //编译器还会经过一次编译
}

前面几篇博客已经分析了第15行的由来,是将c1的地址传递给this指针,将c2作为形参c的别名传递给函数。

2、类中自动建立的函数

在C++中,如果我们定义一个类,它会给我们自动创建六个缺省函数

构造函数析构函数拷贝构造函数赋值函数普通对象的&(取地址符)的重载常对象的&(取地址符)重载

代码示例如下:

class Object
{
public:
    Object()    {}							//构造函数
    ~Object()   {}							//析构函数
    Object(const Object &obj)   {}			//拷贝构造函数
    Object &operator=() {const Object &obj} //赋值函数
    {
        return *this;
    }

    Object *operator&()						//普通对象的&(取地址符)的重载
    {
        return this;
    }

    const Object *operator&() const			//常对象的&(取地址符)重载
    {
        return this;
    }

};

然后,在C11标准下,又增添了两个缺省函数,这里不做深究:

移动构造函数移动赋值函数

3、重载赋值运算符解析

回到最初的例子:

class Object
{
    int value;
public:
    Object ()   {
        cout << "create:" << this << endl;
    }                  //普通构造函数
    Object (int x = 0):value(x) {cout << "create:" << this << endl;}  //缺省构造函数
    ~Object()                       //析构函数
    {
        cout << "~Objcet() " << this << endl;
    }
    Object(Object &obj):value(obj.value)
    {
        cout << "Copy create:" << this << endl;
    }

    int & Value()
    {
        return value;
    }

    const int &Value() const
    {
        return value;
    }  

     Object &operator=(const Object& obj)        //此处加引用
    {
        this->value = obj.value;
        return *this;       //this指针指向objb的地址。赋值函数结束后,objb不会被消亡,所以可以以引用返回
    }

	void operator=(const Object& obj)       //赋值语句不可给this指针加const
    {
        this->value = obj.value;
    }

};

int main()
{
    Object objx(0);
    Object objy(0);
    objy = fun(objx);
    cout << objy.Value() << endl;
    return 0;
}

我们在34行添加一个等号运算符重载函数: void operator=(const Object& obj)

此处不可添加const修饰this指针,因为需要使用this指针作为左值被修改。

问题6:void operator=(const Object& obj) 只能用于 obja = objb,为什么不可以这样使用 obja = objb = objc;

我们逐一分析:

obja = objb = objc;

//当调用等号运算符函数的时候。
obja = objb.operator = (objc);
obja = operator = (&objb,objc);
//如果此处是调用的是 void operator=(const Object& obj) ;
//等号从右向左指向,我们不能把一个void 类型赋给一个obja对象类型。

我们将赋值运算符进行再次重载,丢弃 void 版本:

Object &operator=(const Object& obj)        //此处加引用
{
	this->value = obj.value;
	return *this;       //this指针指向objb的地址。赋值函数结束后,objb不会被消亡,所以可以以引用返回
}

这样就可以使用了。

我们接着上次的深入分析:

obja.operator=(operator=(&objb,objc));
operator=(&obja,operator=(&objb,objc));

问题7:如果遇到obja = obja这种情况,如何赋值呢?

回答:对this指针和形参引用进行判断。

Object &operator=(const Object &obj)
{
    if(this != &obj)
    {
        this->value = obj.value
    }
}

问题8:为什么函数是在栈区构建的,以引用返回打印的不是一个随机值?

运行程序,VS2012中,打印的是一个随机值。

VS2019打印的是一个正常值。

c));

> 问题7:如果遇到obja = obja这种情况,如何赋值呢?
>
> 回答:对this指针和形参引用进行判断。

```cpp
Object &operator=(const Object &obj)
{
    if(this != &obj)
    {
        this->value = obj.value
    }
}

问题8:为什么函数是在栈区构建的,以引用返回打印的不是一个随机值?

运行程序,VS2012中,打印的是一个随机值。

VS2019打印的是一个正常值。

在WIN10系统中,VS2019与操作系统完全结合,安全性更高。当程序多次运行的时候,它的逻辑地址都不一样,这样做的好处是:当病毒入侵时,由于程序的逻辑地址是变化的,病毒不好寻找入侵的入口。

总结

到此这篇关于C++中的运算符重载详解的文章就介绍到这了,更多相关C++运算符重载内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++运算符重载的详细讲解

    加号运算符重载 对于内置数据类型,编译器知道如何运算 但是对于自己封装的类,编译器无法进行运算 这时可以通过自己定义运算符重载进行运算 operator+ 通过成员函数重载+号 #include<iostream> using namespace std; class Person { public: int m_a; int m_b; //通过成员函数实现重载 Person operator+ (Person &p) { //创建一个临时变量 Person temp; temp.m_

  • C++运算符重载限制介绍

    目录 一.重载限制 1.必须至少有一个操作数是用户定义的类型 2.不能违反运算符原来的规则 3.不能创建新运算符 4.禁止名单 5.部分运算符只能通过成员函数重载  文章转自公众号:Coder梁(ID:Coder_LT) 一.重载限制 上一篇我们讲了在类和结构体当中重载运算符,关于运算符的重载并不是随心所欲的.C++给出了一些限制,从而保证了规范,以及程序运行的准确性. 下面我们就来一一来看下: 1.必须至少有一个操作数是用户定义的类型 这句话看不明白没有关系,我们只需要记住它的目的就好了.它的

  • 聊聊C++ 运算符重载知识

    前言 1.运算符重载是一种形式的C++多态. 2.重载运算符可以使代码看起来更加自然. 回顾类 在正常构造类的时候,有些成员方法可以不用写出来,例如在这样一个表示时间的类中,拷贝构造函数只是浅拷贝,和系统默认的步骤是一样的,可以不用写了. 同样,析构函数如果在对象死亡之前没有必须要做的事情,也可以不用写. 所以在下面的例子中,拷贝构造和析构函数可以省略. class Time { public: Time(); Time(const Time& src) { _hour = src._hour;

  • C++运算符重载详情介绍

    文章转自公众号:Coder梁(ID:Coder_LT) C++当中除了函数可以重载之外,其实运算符也是可以重载的.我们之前已经接触过一些,可能大家没有意识到. 举个例子,乘号*,运用在指针上,就是取值的意思,而运用在算数当中,则是乘法的意思.同样一个符号,用在不同的地方,起到了不同的效果.这其实就是一种重载,C++根据操作数的数目和类型来决定要使用哪一种操作. 另外C++允许将运算符重载扩展到用户自定义的类型,也就是结构体和类当中.比如,我们可以将重载加号,对两个对象相加. 其实这种用法也出现过

  • C++中的运算符重载详解

    目录 1.引例 2.类中自动建立的函数 3.重载赋值运算符解析 总结 1.引例 class Complex { private: double Real,Image; public: Complex():Real(0),Image(0) {} Complex(double r, double i) : Real(r),Image(i) {} ~Complex() {} }; int main() { Complex c1(1.2,2.3); Complex c2(45,56); Complex

  • C++中运算符重载详解及其作用介绍

    目录 概述 函数重载 运算符重载 C++ 的运算符 重载运算符的规则 成员函数实现 Complex 加法 运算符重载的方法 多种实现方法 实现 operator+= 三种运算符重载函数 成员函数实现 友元函数实现 输出结果 重载单元运算符 例子 重载二元运算符 例子 重载 I/O 插入运算符 << 提取运算符 >> 总结 概述 运算符重载 (Operator Overloading) 函数重载 重载: 将同一名字重新赋予新的含义. 函数重载: 对一个函数赋予新的含义, 使之实现新功

  • Python的运算符重载详解

    一.前言 运算符重载:为运算符定义方法 所谓重载,就是赋予新的含义同一个运算符可以有不同的功能 二.重载作用 让自定义的实例像内建对象一样进行运算符操作让程序简介易读对自定义对象将运算符赋予新的规则 运算符和特殊方法 运算符重载 # @function:运算符重载 # @Description: 一只萤火虫 class MyInteger: """ 创建一个自定义的整数类型 """ def __init__(self, data=0): # 1.

  • Python入门教程之运算符重载详解

    目录 如何重载Python中的运算符 在 Python中重载比较运算符 重载相等和小于运算符 用于运算符重载的 Python 魔术方法或特殊函数 二元运算符 比较运算符 赋值运算符 一元运算符 运算符重载意味着赋予超出其预定义的操作含义的扩展含义.例如运算符 + 用于添加两个整数以及连接两个字符串和合并两个列表.这是可以实现的,因为 '+' 运算符被 int 类和 str 类重载.您可能已经注意到,相同的内置运算符或函数对不同类的对象显示不同的行为,这称为运算符重载. # Python 程序显示

  • Javascript实现运算符重载详解

    最近要做数据处理,自定义了一些数据结构,比如Mat,Vector,Point之类的,对于加减乘除之类的四则运算还要重复定义,代码显得不是很直观,javascript没有运算符重载这个像C++.C#之类的功能的确令人不爽,于是想"曲线救国",自动将翻译代码实现运算符重载,实现思路其实很简单,就是编写一个解释器,将代码编译.例如: S = A + B (B - C.fun())/2 + D 翻译成 `S = replace(replace(A, '+', replace(replace(B

  • C++中的四个默认成员函数与运算符重载详解

    本文主要给大家介绍了关于C++默认成员函数与运算符重载的相关内容,分享出来公的敬爱啊参考学习,话不多说,来一起看看详细的介绍: 一:类和对象的基础知识:类的定义,访问限定符,面向对象封装性,对象的大小计算等等.(编译环境为VS2015) 面向对象程序设计: 概念:(Object Oriented Programming,缩写:OOP)是一种程序设计范型,同时也是一种程序开发的方法.对象指的是类的实例,将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性.灵活性和扩展性. 类:类的基

  • Python运算符重载详解及实例代码

    Python运算符重载 Python语言提供了运算符重载功能,增强了语言的灵活性,这一点与C++有点类似又有些不同.鉴于它的特殊性,今天就来讨论一下Python运算符重载. Python语言本身提供了很多魔法方法,它的运算符重载就是通过重写这些Python内置魔法方法实现的.这些魔法方法都是以双下划线开头和结尾的,类似于__X__的形式,python通过这种特殊的命名方式来拦截操作符,以实现重载.当Python的内置操作运用于类对象时,Python会去搜索并调用对象中指定的方法完成操作. 类可以

  • C++类与对象之运算符重载详解

    目录 运算符重载 加号运算符重载 左移运算符重载 递增运算符重载 递减运算符重载 赋值运算符重载 关系运算符重载 函数调用运算符重载 总结 运算符重载 运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 加号运算符重载 作用:实现两个自定义数据类型相加的运算 #include <iostream> using namespace std; class Person { public: // 构造函数 Person(int num1, int num2){ thi

  • Python编程基础之运算符重载详解

    目录 学习目标 一.运算符重载 (一)概述 (二)加法运算重载符 1.概述 2.案例演示 总结 学习目标 1.掌握运算符重载 2.会定制对象字符串的形式 一.运算符重载 (一)概述 运算符重载是通过实现特定的方法使类的实例对象支持Python的各种内置操作 .例如:+运算符是类里提供的__add__这个函数,当调用+实现加法运算的时候,实际上是调用了__add__方法. 方法 说明 何时调用方法 __add__ 加法运算 对象加法:x+y,x+=y __sub__ 减法运算 对象减法:x-y,x

  • C++基础知识之运算符重载详解

    目录 运算符重载 方式一,使用成员函数重载运算符需求:把牛肉换猪肉,羊肉换猪肉 方式二,使用非成员函数[友元函数]重载运算符 两种方式的区别 两种方式的选择: 总结 运算符重载 为什么要使用运算符重载 -C/C++的运算符,支持的数据类型,仅限于基本数据类型. 问题:一头牛+一头马 = ?(牛马神兽?) 一个圆 +一个圆 = ? (想要变成一个更大的圆)一头牛 – 一只羊 = ? (想要变成4只羊,原始的以物易物:1头牛价值5只羊) 解决方案: 使用运算符重载 方式一, 使用成员函数重载运算符

随机推荐