首页 > 编程语言 >C++之运算符

C++之运算符

时间:2023-08-25 14:36:31浏览次数:58  
标签:函数 ++ C++ 运算符 operator 内存 重载

运算符函数

在C++中会把运算符当做函数处理,一个表达式,其实可能调用了很多运算符函数来完成计算,这种特性对内建类型没有用,但是对于自建类型而言,通过设计运算符函数能够进行个性化运算,以此提高代码的可读性、易用性,例如string类

Ⅰ.运算符函数的格式:

'#'表示运算符,'O'表示运算符对象

  1. 单目运算符: #O O#

    成员函数:
        [] O::operator#(void)
        {
    
        }
        返回值不确定,唯一的参数就是调用者本身
    全局函数:
        [] operator#(O& o)
        {
    
        }
    某种运算符成员函数、全局函数只能同时实现一个,不能一起实现
    
  2. 双目运算符:    a # b

    注意:左操作数是运算符函数的发起者
    成员函数:
        [] A::operator#(B& b)
        {
    
        }
    全局函数:
        [] operator#(A& a,B& b)
        {
    
        }
    
  3. 运算类的双目运算符     O是类名

    成员函数:a + b
        const O O::operator+(const O& b)const
        {
            return O(x+b.x,y+b.y);
        }
    全局函数: a + b
        const O operator+(const O& a,const O& b)
        {
    
        }
    
Ⅱ.友元

在实现类的全局运算符函数时,可能会使用到类内的私有成员,此时全局函数是没有访问权限的,如果改变私有为公开会破坏类的封装性,如果提供公开的访问函数又非常麻烦,最好的方式是给该全局函数给予独家授权,让其能够访问类内私有成员,这种行为称为把该全局函数设置为友元函数

方式:在类内对全局函数声明,并在声明前加friend

friend cosnt O operator+(const O& a,const O& b);
Ⅲ.输入输出运算符

在C++中 << >> 运算符不光是按位左移、按位右移,同时还是cout该类的输出运算符 cin该类的输入运算符

以下模式背下来

  1. 输出运算符
    由于 << 运算符的调用者是cout对象,我们是无法在该对象的类中去设计一个输出运算符的成员函数,所以只能实现 << 运算的全局函数

    ostream& operator<<(ostream& os,const O& t)
    {
        return os << "输出格式" ;
    }
    
  2. 输入运算符    cin >> num;

    istream& operator>>(istream& is,O& t)
    {
        return is << "输入格式" ;
    }
    

注意:

  1. 由于输出、输入是可以连续进行的,所以返回值还应该是ostream、istream引用

  2. 因为无法在ostream、istream中重载运算符成员函数,所以 << >> 只能重载成全局函数

  3. 如果在重载全局函数中使用到自己类内私有的成员变量,需要声明为友元函数

  4. 输出运算符函数中,第二个参数一定要加const,而输入运算符函数中不能加

Ⅳ.运算类的单目运算符

单目:++/--     !    ~    -    *    &    sizeof

成员函数:    ~    !    -
O O::operator~(void)const
{
    return O(~x,~y);
}

注意:运算对象可以具备常属性,因此需要是常函数,运算的结果只是一个临时值,并且是右值

全局函数:
O operator~(const O& a)
{
    return O(~a.x,~a.y);
}
Ⅴ.自变运算符
  • C++的前后自变左右值问题:
    能位于赋值运算符= 左边的就是左值,反之为右值
    有名称、可以获取到存储地址的称之为左值,反之右值

  • C++前自变:    ++num = 10;    //成功     num = 10
    直接修改原对象,在原对象基础上实现自变,然后将原对象的引用返回,所以操作和返回的一直是原对象,是左值

  • C++后自变: num++ = 10; //报错
    先将原对象的数据存储到临时变量中,接着在原对象基础上自变,然后把临时变量以只读方式返回,并且该临时变量执行语句结束后立即销毁了,无法访问,因此结果是右值

++num++;    //后自变优先级更高,报错
(++num)++;    //先前自变为左值,正确
  1. 前自变运算符:    ++a/--a(四种自变运算符函数背下来,笔试会考)
    成员函数:

    O& O::operator++(void)
    {
        ++操作;
        return *this;
    }
    

    全局函数:

    O& operator++(O& p)
    {
        ++操作;
        return p;
    }
    
  2. 后自变运算符: a++/a--
    哑元:在参数列表中增加一个不使用且无形参名的int哑元类型,唯一目的就是用于区分是前自变还是后自变
    成员函数:

    O O::operator++(int)
    {
        return O(x++,y++);
    }
    

    全局函数:

    O operator++(O& a,int)
    {
        return O(a.x++,a.y++);
    }
    
Ⅵ.特殊的运算符重载函数

*    ->    ( )    [ ]    new    delete

  1. [ ]下标运算符
    想让一个类对象当成数组一样使用,可以考虑重载下标运算符,例如:vector
    可以考虑在下标重载函数中做非法下标的判断

  2. ( )函数运算符
    重载此运算符,可以让一个类对象当作函数一样使用

注意

  • ( ) \ [ ] 均不能实现为全局运算符函数,只能实现成员函数(C++全局中已经有类似的函数实现,所以不让实现)

  • = 赋值运算符函数也不能实现为全局函数,因为类内本身一定有一个=赋值运算符成员函数

  1. 解引用* 和访问成员运算符 ->
    重载这两个运算符可以让类对象像指针一样使用,智能指针就是通过重载这俩运算符从而像使用指针一样的类

  2. new/delete运算符的重载

    void* operator new(size_t size)
    

    C++语法要求重载new运算符的参数必须为size_t,编译器会帮助计算出要申请的字节数并传递,返回值必须为void*,编译器会帮助转换成对应类型指针并返回

    void operator delete(void* ptr)
    

    C++语法要求重载delete的参数必须为void,编译器帮助转换成void传递
    注意
    ①new和delete的成员函数、全局函数格式一样;
    ②如果只是如果只是针对某个类想要重载它的new\delete时,则写为成员函数
    ③如果想要所有类型都执行重载版本,则实现为全局函

    为什么要重载new/deldete?

    ①可以在重载函数中记录每次分配、释放内存的地址、代码情况、次数情况等到日志中,从而方便检查是否出现内存泄漏,以及泄漏位置

    ②对于字节少、且频繁申请、释放的对象,可以在重载函数中给他多分配点内存从而减少产生内存碎片的可能


内存泄漏:内存无法使用,也无法被释放,当再次需要时只能重新申请,然后又重复以上过程,日积月累后会导致系统中可用的内存越来越少
  • 如何尽量避免内存泄漏:谁申请的谁释放,谁知道该释放谁释放

  • 如何判断定位内存泄漏:
    ①查看内存的使用情况,windows 任务管理器 Linux 命令ps -aux
    ②代码分析工具mtrace,检查malloc、free的使用情况
    ③封装新的malloc和free函数,记录调用信息到日志中

内存碎片:已经被释放但是又无法继续使用的内存叫做内存碎片,是由于申请和释放的时间不协调导致的,内存碎片无法避免只能尽量减少

如何减少内存碎片:

  1. 尽量使用栈内存,栈内存不会产生内存碎片

  2. 不要频繁地申请和释放内存

  3. 尽量申请大块内存自己管理


Ⅶ.重载运算符的限制
  1. 不能重载的运算符

    ::  域限定符
    .   直接访问成员的运算符
    ?:  三目运算符
    sizeof 计算字节数
    typeid 获取类型信息的运算符
    
  2. 只能重载为全局函数的运算符

    <<  输出运算符 
    >>  输入运算符
    
  3. 只能重载为成员函数的运算符

    []  
    ()
    =
    ->
    
  4. 运算符重载可以自定义运算符执行过程,但是无法改变运算符的优先级

  5. 运算符的操作数量也不能改变

  6. 不能发明新的运算符

建议:
  1. 重载运算符要遵循一致性原则,不要随意改变运算符本身的含义不要忘记实现运算符重载函数的初衷

  2. 不要忘记实现运算符重载函数的初衷,为了提高可读性,不要随意炫技

标签:函数,++,C++,运算符,operator,内存,重载
From: https://www.cnblogs.com/wangqiuji/p/17656820.html

相关文章

  • C++单例模式
    单例模式什么是单例模式:只能实例化一个类对象(全局有且只有一个类的static实例)使用场景:进程管理器、日志管理器、网站访问计数器、应用配置程序、线程池、服务器的连接管理器实现单例模式的原理/步骤1、禁止在类外随意实例化对象,把构造函数/拷贝构造都私有化private2、确保......
  • c++ stl std::sort使用例子
    classUser{public:int32_tm_fight_power;private:int32_tm_level;};boolCenterData::compare(constUser*left,constUser*right){if(left->m_fight_power!=right->m_fight_power){returnleft->m_fight_power>ri......
  • C++异常处理:try、throw、catch
    ​1.引子程序在运行时,总是会遇到一些错误,这些错误或者是导致程序无法运行,例如操作空指针,或是不符合正常运行的规律,例如除以0。因此,在C++程序当中就必须添加对应异常处理机制,在检测到指定的程序异常时,为保证程序正常运行,需要跳转至异常处理程序当中。常规的错误处理有以下几种解......
  • C++静态成员(static)
    静态成员(static)什么是静态成员:被static修饰的成员/成员函数就叫静态成员,不管有多少对象,静态成员只有一份存于公共内存中。设计静态数据成员目的是信息共享和信息交流普通成员特点:成员变量:每个类对象中都有一份属于自己的成员变量,相互独立、没有关联。普通成员与对象绑定,随......
  • C++11 四种强制类型转换的区别
    static_cast:指针强转,如果某个基类有多个子类,基类的指针实际是指向A类的对象,但使用强转为B类对象,运行时会报错,静态强转没做检测dynamic_cast:只能用于虚函数类,子类与父类指针互转,会检测,转换失败为返回空,不会崩const_cast:用于转换常量,修改常量,先用一个常......
  • C++拷贝构造、赋值函数
    拷贝构造拷贝构造就是一种特殊版本的构造函数,格式:类名(const类名&that){    //执行给每个成员变量进行赋值  }什么时候会调用拷贝构造:当使用旧对象(已new的)给新对象(新new的)初始化时,会自动调用拷贝构造    Testt1;//调用无参构造Testt2=t1......
  • C++this指针、常函数
    this指针this指针的类型:类类型*const。不能被修改和赋值。只能在成员函数的内部使用。全局函数、静态函数都不能使用this.this指针本质上其实是一个成员函数的形参(栈),是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。this指针是成......
  • C++静态成员和单例模式
    一、静态成员Ⅰ.什么是静态成员:被static修饰的成员变量和成员函数就叫静态成员Ⅱ.普通成员的特点:成员变量:每个类对象中都有一份属于自己的成员变量,相互之间没有关联、独立的成员函数:隐藏着一个this指针,接收调用者的地址用于区分调用者Ⅲ.静态成员的特点:静态成员变......
  • C++对象的创建和销毁过程分析
    对象的创建和销毁过程分析1、对象的创建过程①给对象划分内存空间(栈、堆)②执行初始化列表根据继承表的顺序调用父类的无参构造或有参构造通过:父类(val)调用父类的有参构造根据成员变量的定义顺序调用类类型成员的无参构造或有参构造通过:类类型成员名(val)调用类类型成员......
  • C++面向对象、类和对象、访问控制限定符
    面向对象和面向过程面向过程:关注如何解决问题,以及解决问题的步骤面向对象:关注的解决问题的"人"即"对象",以及实现能解决问题的"对象"注意:面向对象的细节的本质上还是面向过程,因此面向对象不是解决问题的捷径,而是以更高的维度去思考问题面向对象的四个特性:抽象:先找出(想象)......