标签:
//全局函数和静态函数的转换 #include <iostream> using namespace std; ? class Test { public: ????Test(int a = 0, int b = 0) ????{ ????????this->a = a; ????????this->b = b; ????} public: ????int a; ????int b; public: ????//全局函数 ????Test T_add(Test &t1, Test &t2) ????{ ????????Test t3; ????????t3.a = t1.a + t2.a; ????????t3.b = t1.b + t2.b; ????????return t3; ????} ????Test& add(Test &t2) //面向对象编程 ????{ ????????a = a + t2.a; ????????b = b + t2.b; ????????return *this; ????} }; //全局函数 Test T_add(Test &t1, Test &t2) { ????Test t3; ????t3.a = t1.a + t2.a; ????t3.b = t1.b + t2.b; ????return t3; } ? Test T_add01(Test *pthis, Test &t1, Test &t2) { ????Test t3; ????t3.a = t1.a + t2.a; ????t3.b = t1.b + t2.b; ????return t3; } //从成员函数转换为全局函数,只需要加一个this指针(一个指向本类的指针) //从全局函数转换为类的成员函数,只需要减去一个左操作数 void Demo01() { ????Test t1(2, 3), t2(3, 4); ????Test t3 = T_add(t1, t2); ????t3 = t1.T_add(t1, t2); } void main() { ????system("pause"); } |
从成员函数转换为全局函数,只需要加一个this指针(一个指向本类的指针),而从从全局函数转换为类的成员函数,只需要减去一个左操作数即可,正如上面的代码所示。
#include <iostream> using namespace std; ? class Complex { public: ????int a; ????int b; public: ????Complex(int a = 0, int b = 0) ????{ ????????this->a = a; ????????this->b = b; ????} ????void print() ????{ ????????printf("%d+%di\n", a, b); ????} ? }; Complex add(Complex &lop, Complex &rop) { ????Complex result; ????result.a = lop.a + rop.a; ????result.b = lop.b + rop.b; ????return result; } ? Complex operator+(Complex &lop, Complex &rop)//重载 { ????Complex result; ????result.a = lop.a + rop.a; ????result.b = lop.b + rop.b; ????return result; } void Demo01() { ????Complex c1(1, 2), c2(3, 4); ????//c1 = c1 + c2; //编译器压根不知道怎么加,但是编译器会给你提供一种机制,会让你实现自定义加操作 ????Complex c3 = add(c1, c2); //直接调用函数add } void Demo02() { ????Complex c1(1, 2), c2(3, 4); ????//操作符重载首先是通过函数实现的 ????//+操作符有两个参数,左操作数和右操作数,特别留意左操作数 ????Complex c3 = c1 + c2; //实现了重载 ????//Complex c3 = operator+(c1, c2);//这样写也不会错 } ? void main() { ????Demo02(); ????system("pause"); } |
一般的类变量是设置成private属性的,因此我们一般都用友元函数实现运算符重载。
#include <iostream> using namespace std; ? class Complex { private: ????int a; ????int b; public: ????Complex(int a = 0, int b = 0) ????{ ????????this->a = a; ????????this->b = b; ????} ????//通过友元函数实现操作符重载 ????friend Complex operator+(Complex &lop, Complex &rop); ????friend Complex &operator++(Complex &lop); ????friend Complex operator++(Complex &lop, int/*占位符*/); ????//通过类的成员函数实现减号操作 ????Complex operator-(Complex &rop) //左操作数隐藏在this指针里面 ????{ ????????Complex res; ????????res.a = a - rop.a; ????????res.a = b - rop.b; ????????return res; ????} ????Complex &operator--() ????{ ????????a--; ????????b--; ????????return *this; ????} ????Complex operator--(int) //后置--的成员函数实现 ????{ ????????Complex tmp = *this; ????????this->a--; ????????this->b--; ????????return tmp; ????} ????void print() ????{ ????????printf("%d + %di\n", a, b); ????} ? }; ? Complex operator++(Complex &lop, int/*占位符*/) { ????Complex tmp = lop; ????lop.a++; ????lop.b++; ????return tmp; } //全局函数原型推导 Complex &operator++(Complex &lop) { ????lop.a++; ????lop.b++; ????return lop; } Complex operator+(Complex &lop, Complex &rop) { ????Complex result; ????result.a = lop.a + rop.a; ????result.b = lop.b + rop.b; ????return result; } void Demo01() { ????Complex c1(1, 2), c2(3, 4); ????//c1 = c1 + c2; //编译器压根不知道怎么加,但是编译器会给你提供一种机制,会让你实现自定义加 ????Complex c4 = c1 - c2; ????Complex c5 = c1.operator-(c2); ????//目标,通过类的成员函数完成操作符重载 ????//1.要承认操作符操作是一个函数,要写函数原型 ????//2.写出函数调用语言 ????//3.完善函数原型 ? } void Demo02() { ????Complex c1(1, 2), c2(3, 4); ????//Complex c3 = operator+(c1, c2); ????//操作符重载首先是通过函数实现的 ????//+操作符有两个参数,左操作数和右操作数,特别留意左操作数 ????Complex c3 = c1 + c2; ? } ? void Demo03() { ????Complex c1(1, 2), c2(3, 4); ????c1++; ????c1.print(); ????--c2; ????c2++; ????//先使用c2的属性,然后让属性+++ ????//operator++(c2, int/*占位符*/);//后置++ ????c2.print(); ????//成员函数实现后置-- } ? void main() { ????Demo03(); ????system("pause"); } |
使用友元函数和类的成员函数都可以实现操作符重载,正如同前面所提到的,成员函数由于已经包含了this指针,所以省略了一个操作数,其实两者差别不大。不过也存在差别,成员函数和友元函数重载操作符各有用处。规范的写法是,一般可以用成员函数实现的操作符重载就不用友元函数,所以使用友元函数重载的地方就很少了,一处场景如下下段代码所示。
关于前置++和后置++需要注意几点:
前置++的版本一般是这么写:foo& operator++() //前置++,前置返回引用
后置++一般这么写:foo operator++(int) //后置++,后置返回对象
前置返回引用,后置返回对象,这是通用做法。
class foo { public: ????foo operator++() //后置++,后置返回对象 ????{ ????????a++; ????????return *this; ????} ????foo& operator++(int) //前置++,前置返回引用,int占位符,只是标记,将前置和后置区分开来 ????{ ????????a++; ????????return *this; ????} public: ????foo(int a = 0) ????{ ????????this->a = a; ????} private: ????int a; }; |
在实际中,我们一般不用友元函数重载运算符,一般都用成员函数,但是使用友元函数重载运算符也有用武之地,下面是规范的写法:
#include <iostream> using namespace std; ? class Complex { private: ????int a; ????int b; public: ????Complex(int a = 0, int b = 0) ????{ ????????this->a = a; ????????this->b = b; ????} ????//通过类的成员函数实现减号操作 ????Complex operator-(Complex &rop) //左操作数隐藏在this指针里面 ????{ ????????Complex res; ????????res.a = a - rop.a; ????????res.a = b - rop.b; ????????return res; ????} ????Complex operator+(Complex &rop) //左操作数隐藏在this指针里面 ????{ ????????Complex res; ????????res.a = a + rop.a; ????????res.a = b + rop.b; ????????return res; ????} ????Complex &operator++() ????{ ????????a++; ????????b++; ????????return *this; ????} ????Complex operator++(int) //后置--的成员函数实现 ????{ ????????Complex tmp = *this; ????????this->a++; ????????this->b++; ????????return tmp; ????} ????Complex &operator--() ????{ ????????a--; ????????b--; ????????return *this; ????} ????Complex operator--(int) //后置--的成员函数实现 ????{ ????????Complex tmp = *this; ????????this->a--; ????????this->b--; ????????return tmp; ????} ????void print() ????{ ????????printf("%d + %di\n", a, b); ????} ????friend ostream& operator<<(ostream &out, Complex &op); //这里才是friend函数的真正用武之地 protected: private: ? }; ? ostream& operator<<(ostream &out, Complex &op) { ????out << op.a << " " << op.b << endl; ????return out; } void Demo01() { ????Complex c1(1, 2), c2(3, 4); ????int a = 10; ????char *p = "abc"; ????cout << p << endl; ????//没有办法在cout类里面添加函数operator<<只能通过全局函数实现 ????cout << c1; ????cout << c1 << endl << "链式编程测试" << endl; ????//若void operator<<(ostream &out, Complex &op); ????//operator<<(cout, &c1); ????//void << endl; ????//函数返回值当左值的时候,需要返回一个对象的引用 ? } ? void main() { ????Demo01(); ????system("pause"); } |
特别需要注意的地方是,如果ostream& operator<<(ostream &out, Complex &op)写成了void operator<<(ostream &out, Complex &op),虽然执行cout << c1;不会出错,但是执行cout << c1 << endl << "链式编程测试" << endl;会出错,这是因为operator=的返回值的缘故,cout << c1相当于执行operator<<(cout, c1),返回void,接下来执行void << endl,不错才怪。
同时,上面的ostream& operator<<(ostream &out, Complex &op)是友元函数运用的绝好时期,因为cout并没有在成员函数里实现operator<<(Complex &op),当然它也不可能实现,怎么办呢?恰好运用友元函数可以解决这个问题。
接下来是运算符重载的一个很好的例子:
/*Array.h*/ #ifndef _ARRAY_H_ #define _ARRAY_H_ #include <iostream> class Array { private: ????int mLength; ????int* mSpace; ? public: ????Array(int length); ????Array(const Array& obj); ????int length(); ????void setData(int index, int value); ????int getData(int index); ????~Array(); public: ????int& operator[](int index); ????Array& operator=(Array &rop); ????bool operator==(Array &rop); ????bool operator!=(Array &rop); }; ? ? //[] = == != // ? ? #endif |
?
/*Array.cpp*/ #include "iostream" #include "Array.h" using namespace std; ? //区别 如果不加引用会构造一个匿名对象(临时对象) //开销会非常大 Array::Array(int length) { ????if (length < 0) ????{ ????????length = 0; ????} ? ????mLength = length; ????mSpace = new int[mLength]; } ? Array::Array(const Array& obj) { ????mLength = obj.mLength; ? ????mSpace = new int[mLength]; ? ????for (int i = 0; i<mLength; i++) ????{ ????????mSpace[i] = obj.mSpace[i]; ????} } ? int Array::length() { ????return mLength; } ? void Array::setData(int index, int value) { ????mSpace[index] = value; } ? int Array::getData(int index) { ????return mSpace[index]; } ? Array::~Array() { ????mLength = -1; ????delete[] mSpace; } ? //需要当左值,返回引用 //返回引用是要注意生命周期 /************************************************************************/ /* Complex &operator-(operator &rop) { Complex tmp; tmp.a = this.a - rop.a; tmp.b = this.b - rop.b; return tmp; //这样返回会出问题 return rop;//这样返回没问题 } */ /************************************************************************/ //printf("%d", a[i]); //a[i] = 10; int& Array::operator[](int index) //函数返回值当左值 a[i] = 10; { ????if (index > mLength) ????{ ? ????} ????return mSpace[index]; } ? //测试用例 //a2 = a3; //a1 = a2 = a3;连等操作 =从右向左 先执行a2 = a3返回 a2再执行 a1 = a2; //a1.operator=(a2.operator=(a3))) //函数返回值当左值 Array& Array::operator=(Array &rop) { ????if (mSpace != NULL) ????{ ????????delete[]mSpace; ????????mLength = 0; ????????mSpace = NULL; ????} ????mSpace = new int[rop.mLength]; ????mLength = rop.length(); ????for (int i = 0; i < rop.mLength; ++i) ????{ ????????mSpace[i] = rop.getData(i); ????} ????return *this; } bool Array::operator==(Array &rop) {//先判断长度是否相等,在判断数据是否相等 ????if (rop.length() != mLength) ????{ ????????return false; ????} ????for (int i = 0; i < mLength; ++i) ????{ ????????if (mSpace[i] != rop.getData(i)) ????????{ ????????????return false; ????????} ????} ????return true; } bool Array::operator!=(Array &rop) { ????return !this->operator==(rop); } |
?
标签:
原文地址:http://www.cnblogs.com/lishuhuakai/p/4523481.html