嵌入式linux C++语言(六)——运算符重载

嵌入式linux C++语言(六)——运算符重载

运算符重载的本质是函数重载。

一、重载基础

1、运算符重载的语法

返值类型 operator 运算符名称(形参表列)
{
    重载实体;
}

2、友元重载

可以将运算符重载函数声明位友元函数

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(float x=0, float y=0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
    friend const Complex operator+(const Complex &c1,const Complex &c2);
private:
    float _x;
    float _y;
};
const Complex operator+(const Complex &c1,const Complex &c2)
{
    return Complex(c1._x + c2._x,c1._y + c2._y);
}
int main()
{
    Complex c1(2,3);
    Complex c2(3,4);
    c1.dis();
    c2.dis();
    // Complex c3 = c1+c2;
    Complex c3 = operator+(c1,c2);
    c3.dis();
    return 0;
}

3、成员重载

将运算符重载函数声明为类成员函数

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(float x=0, float y=0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
    friend const Complex operator+(const Complex &c1,const Complex &c2);
    const Complex operator+(const Complex &another);
private:
    float _x;
    float _y;
};
const Complex operator+(const Complex &c1,const Complex &c2)
{
    cout<<"友元函数重载"<<endl;
    return Complex(c1._x + c2._x,c1._y + c2._y);
}
const Complex Complex::operator+(const Complex & another)
{
    cout<<"成员函数重载"<<endl;
    return Complex(this->_x + another._x,this->_y + another._y);
}
int main()
{
    Complex c1(2,3);
    Complex c2(3,4);
    c1.dis();
    c2.dis();
    // Complex c3 = c1+c2;
    // Complex c3 = operator+(c1,c2);
    Complex c3 = c1+c2; //优先调用成员函数重载??
    c3.dis();
    return 0;
}

4、运算符重载的规则

A、C++不允许用户自己定义新的运算符,只能对已有的 C++运算符进行重载。
B、C++语言中大部分运算符都可以重载,成员选择符(.)、成员对象选择符(.*)、域解析操作符(::)、条件操作符(?:)、sizeof不可以重载。除了赋值号(=)外,基类中重载的操作符都将被派生类继承。

C、重载不能改变运算符运算对象(即操作数)的个数。

D、重载不能改变运算符的优先级别。

E、重载不能改变运算符的结合性。

F、重载运算符的函数不能有默认的参数

G、重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。参数不能全部是 C++的标准类型,以防止用户修改用于标准类型数据成员的运算符的性质。

H、用于类对象的运算符一般必须重载,但有两个例外,运算符”=“和运算符”&“不
必用户重载。

I、应当使重载运算符的功能类似于该运算符作用于标准类型数据时候时所实现的功能。

J、运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数。

二、重载实例

1、双目运算符重载

形式:L#R
全局函数:operator#(L,R);
成员函数:L.operator#(R)

operator+=实例:

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(float x=0, float y=0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
    Complex& operator+=(const Complex &c)
    {
        this->_x += c._x;
        this->_y += c._y;
        return * this;
    }
private:
    float _x;
    float _y;
};

2、单目运算符重载

形式:#M 或 M#
全局函数:operator#(M)
成员函数:M.operator#()

operator-实例:

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(float x=0, float y=0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
    const Complex operator-(void) const
    {
        return Complex(-_x,-_y);
    }
private:
    float _x;
    float _y;
};

3、流输入输出运算符重载

函数形式
istream & operator>>(istream &,自定义类&);
ostream & operator<<(ostream &,自定义类&);

流输入输出运算符重载通过友元来实现,避免修改 c++的标准库。

operator<< 和operator>>实例:

class Complex
{
public:
    Complex(float x=0, float y=0)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
    friend ostream & operator<<(ostream &os, const Complex & c);
    friend istream & operator>>(istream &is, Complex &c);
private:
    float _x;
    float _y;
};
ostream & operator<<(ostream &os, const Complex & c)
{
    os<<"("<<c._x<<","<<c._y<<")";
    return os;
}
istream & operator>>(istream &is, Complex &c)
{
    is>>c._x>>c._y;
    return is;
}

三、运算符重载总结

1、不可以重载的运算符

. (成员访问运算符)
.* (成员指针访问运算符)
:: (域运算符)
sizeof (长度运算符)
?: (条件运算符)

2、只能重载为成员函数的运算符

= 赋值运算符
[] 下标运算符
() 函数运算符
-> 间接成员访问

3、运算符重载与友元

A、一个操作符的左右操作数不一定是相同类型的对象,这就涉及到将该操作符函数定义为谁的友元,谁的成员问题。
B、一个操作符函数,被声明为哪个类的成员,取决于该函数的调用对象(通常是左操作数)。
C、一个操作符函数,被声明为哪个类的友员,取决于该函数的参数对象(通常是右操作数)。

#include <iostream>
using namespace std;
class Mail;
class Sender
{
public:
    Sender(string s):_addr(s){}
    Sender& operator<<(const Mail & mail); //成员
private:
    string _addr;
};
class Mail
{
public:
    Mail(string _t,string _c ):_title(_t),_content(_c){}
    friend Sender& Sender::operator<<(const Mail & mail);
    //友元
private:
    string _title;
    string _content;
};
Sender& Sender::operator<<(const Mail & mail)
{
    cout<<"Address:"<<mail._addr<<endl;
    cout<<"Title :"<<mail._title<<endl;
    cout<<"Content:"<<mail._content<<endl;
    return *this;
}
int main()
{
    Sender sender("[email protected]");
    Mail mail("note","meeting at 3:00 pm");
    Mail mail2("tour","One night in beijing");
    sender<<mail<<mail2;
    return 0;
}

四、类型转换

标准类型之间的转换一般有隐式和显示转换,用户自定义类型间的转换则需要自定义专门的转换函数。

A、转化函数定义在源对象类(待转化对象中)中,是转化源的成员函数。
B、一旦为转换源类型提供了到目标类型的转化操作符函数,就可以将源类型对象以隐式转化的方式得的目标类型的对象。
C、应用于构造及初始化,赋值,传参,返回等等场合。

1、标准类型间转换

A、隐式转换

5.0/8

B、显示转换

(float)5/8

2、用类型转换构造函数进行类型转换

转换构造函数格式
class 目标类
{
    目标类(const 源类 & 源类对象引用){
    根据需求完成从源类型到目标类型的转换
        }
}

#include <iostream>
using namespace std;
class Point3D;
class Point2D
{
public:
    Point2D(int x,int y)
        :_x(x),_y(y){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
    friend Point3D;
private:
    int _x;
    int _y;
};
class Point3D
{
public:
    Point3D(int x,int y,int z)
        :_x(x),_y(y),_z(z){}
    Point3D(const Point2D &p)
    {
        this->_x = p._x;
        this->_y = p._y;
        this->_z = 0;
    }
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<","<<_z<<")"<<endl;
    }
private:
    int _x;
    int _y;
    int _z;
};
int main()
{
    Point2D p2(1,2);
    p2.dis();
    Point3D p3(3,4,5);
    p3.dis();
    Point3D p3a = p2;
    p3a.dis();
    return 0;
}

3、用类型转换操作符函数进行转换

类型转化函数格式
class 源类{
    operator 转化目类型(void){
    根据需求完成从源类型到目标类型的转换
    }
}

#include <iostream>
using namespace std;
class Point3D;
class Point2D
{
public:
    Point2D(int x,int y)
        :_x(x),_y(y){}
    operator Point3D();
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<")"<<endl;
    }
private:
    int _x;
    int _y;
};
class Point3D
{
public:
    Point3D(int x,int y,int z)
        :_x(x),_y(y),_z(z){}
    void dis()
    {
        cout<<"("<<_x<<","<<_y<<","<<_z<<")"<<endl;
    }
private:
    int _x;
    int _y;
    int _z;
};
Point2D::operator Point3D()
{
    return Point3D(_x,_y,0);
}
int main()
{
    Point2D p2(1,2);
    p2.dis();
    Point3D p3(3,4,5);
    p3.dis();
    Point3D p3a = p2;
    p3a.dis();
    return 0;
}

五、重载应用

1、函数操作符

把类对象像函数名一样使用。仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个 operator(),这个类就有了类似函数的行为,就是一个仿函数类了。

定义:

class 类名
{
  返值类型 operator()(参数类型)
    函数体
}

#include <iostream>
#include <vector>
using namespace std;
class Sqr
{
public:
    int operator()(int i)
    {
        return i*i;
    }
    double operator ()(double d)
    {
        return d*d;
    }
};
int main()
{
    Sqr sqr;
    int i = sqr(4); //sqr.opreator()(4);
    double d = sqr(5.5); //sqr.operator()(5.5);
    cout<<i<<endl;
    cout<<d<<endl;
    return 0;
}

函数操作符主要应用于STL和模板

2、堆内存操作符

定义:

operator new
      operator delete
      operator new[]
      operator delete[]

A、全局函数重载

#include <iostream>
#include <stdlib.h>
using namespace std;
 
class A
{
public:
    A()
    {
        cout<<"A constructor"<<endl;
    }
    ~A()
    {
        cout<<"A destructor"<<endl;
    }
private:
    int a;
};
 
void * operator new (size_t size)
{
    cout<<"new "<<size<<endl;
    return malloc(size);
}
void operator delete(void *p)
{
    cout<<"delete"<<endl;
    free(p);
}
void * operator new[] (size_t size)
{
    cout<<"new[] "<<size<<endl;
    return malloc(size);
}
void operator delete[](void *p)
{
    cout<<"delete[] "<<endl;
    free(p);
}
 
int main()
{
    int *p = new int;
    delete p;
    int *pa = new int[20];
    delete []pa;
    A * cp = new A;
    delete cp;
    A * cpa = new A[20];
    delete []cpa;
    return 0;
}

B、类成员函数重载

#include <iostream>
#include <stdlib.h>
using namespace std;
 
class A
{
public:
    A()
    {
        cout<<"A constructor"<<endl;
    }
    ~A()
    {
        cout<<"A destructor"<<endl;
    }
    void * operator new (size_t size)
    {
        cout<<"new "<<size<<endl;
        return malloc(size);
    }
    void operator delete(void *p)
    {
        cout<<"delete"<<endl;
        free(p);
    }
    void * operator new[] (size_t size)
    {
        cout<<"new[] "<<size<<endl;
        return malloc(size);
    }
    void operator delete[](void *p)
    {
        cout<<"delete[] "<<endl;
        free(p);
    }
    private:
        int a;
};
 
int main()
{
    // int *p = new int;
    // delete p;
    // int *pa = new int[20];
    // delete []pa;
    A * cp = new A;
    delete cp;
    A * cpa = new A[20];
    delete []cpa;
    return 0;
}
时间: 2024-12-23 18:17:15

嵌入式linux C++语言(六)——运算符重载的相关文章

嵌入式Linux C语言(六)——内存字节对齐

嵌入式Linux C语言(六)--内存字节对齐 一.内存字节对齐简介 1.内存字节对齐 计算机中内存空间都是按照字节划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但是在程序实际编译过程中,编译器会对数据类型在编译过程中进行优化对齐,编译器会将各种类型数据按照一定的规则在空间上排列,而不是顺序的排放,这就是内存字节对齐. 2.内存字节对齐原因 不同硬件平台对存储空间的处理是不同的.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如某些架构的CPU在访问一个没有进行对齐的变量

嵌入式linux C++语言(二)——C++对C语言基础语法的扩展

嵌入式linux C++语言(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.类型增强 1.类型检查更严格 在C语言中: const int a = 100; int *p = &a; 在C++语言中: const int a = 100;//必须在定义的时候初始化 const int *p = &a; 在C++语言中不能隐式转换数据类型. error: invalid conversion

嵌入式linux C++语言(一)——C++简介

嵌入式linux C++语言(一)--C++简介 一.C++简介 C语言作是结构化和模块化的语言,适合处理较小规模的程序.对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言并不合适.为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming)思想,支持面向对象的程序设计语言应运而生.Smalltalk 就是当时问世的一种面向对象的语言.在实践工作中,由于C语言的广泛使用,在C语言的基础上根据面向对象的思想发展了C语言,形成了C

嵌入式 Linux C语言——C语言基础

嵌入式 Linux C语言--C语言基础 一.数据类型 1.基本数据类型 数据类型是创建变量的模型.变量名是连续存储空间的别名,程序中使用变量命名存储空间,通过变量可以使用存储空间.变量所占的内存大小取决于创建变量的数据类型. 2.有符号和无符号 有符号数中数据类型的最高位用于标识数据的符号,最高位为1表示为负数,最高位为0表示为正数. 计算机中有符号数通常使用补码表示,正数的补码为正数本身,负数的补码为负数的绝对值的各位取反后加1. 计算机中无符号数通常使用原码表示,无符号数默认为正数,没有符

嵌入式linux C++语言(四)——类与对象

嵌入式linux C++语言(四)--类与对象 类的设计和使用如下: #include <iostream>#include <stdlib.h>#include <stdio.h>#include <string.h>using namespace std;class Stack{public:    Stack(int size=1024);    ~Stack();    void init();    bool isEmpty();    bool

嵌入式 Linux C语言(八)——存储类型、作用域、生命周期、链接属性

嵌入式 Linux C语言(八)--存储类型.作用域.生命周期.链接属性 一.存储类型 C语言中,每个变量和函数都有两个属性:数据类型和数据的存储类型. 变量的存储类型是指存储变量值的内存类型.变量的存储类型决定变量何时创建.何时销毁以及它的值将保持多久.计算机中有三个地方可以用于存储变量:普通内存,运行时堆和栈,硬件寄存器.变量的存储类型取决于声明变量的位置. C语言存储类别说明符: 说明符 用    法 auto 只在代码块内变量声明中被允许, 表示变量具有本地生存期 extern 出现在顶

嵌入式Linux C语言(二)——指针

嵌入式Linux C语言(二)--指针 指针是C语言中广泛使用的一种数据类型,是C语言的灵魂.指针提供了动态操控内存的机制,强化了对数据结构的支持,而且实现了访问硬件的功能.学习指针是学习C语言中最重要的一环,能否正确理解和使用指针是我们是否掌握C语言的一个标志. 一.指针的概念 在计算机中,所有的数据都是存放在内存中的,一般把内存中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不一样,如int占用4个字 节,char占用1个字节.为了正确地访问内存单元,必须为每个内存单元编上号.

嵌入式linux C++语言(七)——继承与派生

嵌入式linux C++语言(七)--继承与派生 一.继承 在C++编程中软件可重用性(software reusability)是通过继承(inheritance)机制来实现的.类的继承,是新的类从已有类那里得到已有的特性.或从已有类产生新类的过程就是类的派生.原有的类称为基类或父类,产生的新类称为派生类或子类. 派生类的声明:class 派生类名:[继承方式] 基类名{派生类成员声明:};    一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承. 继承方式规

嵌入式 Linux C语言(七)——结构体

嵌入式 Linux C语言(六)--结构体 一.结构体简介 1.结构体定义 结构体定义一般有两种方法较为常用: 第一种方法: struct person{ char *name; unisgned int age; }; 第二种方法: typedef struct person{ char *name; unsigned int age; }Person; person实例声明如下: Person person;//声明一个person对象 Person *ptrPerson = (Person