嵌入式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; }