友元函数和运算符重载
友元
一个常规的成员函数声明描述了三件在逻辑上相互不同的事情
①该函数能访问类声明中的私用部分
②该函数位于作用域之中
③该函数必须经由一个对象去激活(有一个this指针)
通过将函数声明为static,可以让他只有前两种性质
通过将一个函数声明为友元可以使他只具有第一种性质
一个常规的成员函数声明描述了三件在逻辑上相互不同的事情
①该函数能访问类声明中的私用部分
②该函数位于作用域之中
③该函数必须经由一个对象去激活(有一个this指针)
通过将函数声明为static,可以让他只有前两种性质
通过将一个函数声明为友元可以使他只具有第一种性质
单(++,--)、双目运算符(+,-,*,/,%,|,&,+=,-=,*=,/=)的重载(双目重载绝大多数只考虑对象与对象进行的操作),输入输出运算符作为友元函数的重载。
//Test1.h #include<iostream> using namespace std; class INT { friend INT operator+(int a, const INT &t); friend ostream& operator<<(ostream &out, const INT &t); friend istream& operator>>(istream &in, INT &t); private: int a; long b; public: INT(int _a=0,long _b=0):a(_a),b(_b) { this->a=_a; this->b=_b; } INT(INT &t) { this->a = t.a; this->b = t.b; } ~INT(){} INT& operator=(const INT &t); INT operator+(const INT &t); INT operator+(int i); INT operator-(const INT &t); INT operator*(const INT &t); INT operator/(const INT &t); INT operator%(const INT &t); INT operator&(const INT &t); INT operator|(const INT &t); INT& operator+=(const INT &t);//因为结果返回本身,因此使用引用更快捷 INT& operator-=(const INT &t); INT& operator*=(const INT &t); INT& operator/=(const INT &t); INT& operator%=(const INT &t); INT& operator++();//++a引用返回this就不用拷贝构造了 INT operator++(int);//后++比前++多一个参数//a++ INT& operator--(); INT operator--(int); }; INT& INT::operator%=(const INT &t) { this->a %= t.a; this->b %= t.b; return *this; } INT& INT::operator/=(const INT &t) { if(t.a != 0) { this->b /= t.b; this->a /= t.a; return *this; } exit(0); } INT& INT::operator*=(const INT &t) { this->a *= t.a; this->b *= t.b; return *this; } INT& INT::operator-=(const INT &t) { this->a -= t.a; this->b -= t.b; return *this; } INT& INT::operator+=(const INT &t) { this->a += t.a; this->b += t.b; return *this; } INT INT::operator|(const INT &t) { return(this->a|t.a, this->b|t.b); } INT INT::operator&(const INT &t) { return(this->a&t.a, this->b&t.b); } INT INT::operator%(const INT &t) { return(this->a%t.a, this->b%t.b); } INT INT::operator/(const INT &t) { if(t.a != 0) return(this->a/t.a,this->b/t.a); exit(0); } INT INT::operator*(const INT &t) { return (this->a*t.a, this->b*t.b); } INT INT::operator++(int) { INT tmp(this->a,this->b); ++this->a; ++this->b; return tmp; } INT& INT::operator++() { ++this->a; ++this->b; return *this; } INT INT::operator--(int) { INT tmp(this->a); --this->a; --this->b; return tmp; } INT& INT::operator--() { --this->a; --this->b; return *this; } INT INT::operator+(const INT &t) { return(this->a+t.a,this->b+t.b);;//将(this->a+t.a)隐式转换为一个无名的临时对象。 } INT INT::operator+(int i) { INT tmp(this->a+i,this->b); return tmp; } INT INT::operator-(const INT &t) { return(this->a-t.a,this->b-t.b); } INT& INT::operator=(const INT &t) { if(this != &t) { this->a = t.a; this->b = t.b; } return *this; } INT operator+(int a, const INT &t) { INT tmp(a+t.a,t.b);//此处使用临时对象的原因是防止直接返回无名临时对象时其私有数据被初始化 return tmp; } ostream& operator<<(ostream &out, const INT &t) { out<<"("<<t.a<<", "<<t.b<<")"; return out; } istream& operator>>(istream &in, INT &t) { in>>t.a>>t.b; return in; }
友元函数
1.友源函数不是类的成员函数,在函数体中访问对象的成员,必须用对象名加运算符“.”加对象成员名。但是
友源函数可以访问类中的所有成员,一般函数只能访问类中的公有成员。
2.友源函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护成分,但结果一样。
3.某类的友元函数的作用域并非该类作用域,如果该友元函数是另一类的成员函数,其作用域为另一类的作用域,否则与一般函数相同。
友源函数可以访问类中的所有成员,一般函数只能访问类中的公有成员。
2.友源函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护成分,但结果一样。
3.某类的友元函数的作用域并非该类作用域,如果该友元函数是另一类的成员函数,其作用域为另一类的作用域,否则与一般函数相同。
//Test.cpp
#include<iostream> #include"Test1.h" using namespace std; void main() { INT a(5); INT b(2); INT c = a&b; INT d = a|b; INT s; c += d; c -= d; c *= d; d = INT(10,15); c /= d; c %= d; cout<<c<<endl; cin>>s; a = 10 + a; a = a + 10; }
关于加法的函数有三个分别解决:对象与对象相加、 对象与数字相加(这两个是类的成员函数),数字与对象相加(友元函数)
输入输出运算符均被重载为友元函数,但是输出运算符可以被重载为类的成员函数,只不过调用那时有些不符合正常习惯
#include<iostream> using namespace std; class Test { private: int a; int b; public: Test(int _a=0, int _b=0):a(_a),b(_b) { this->a = _a; this->b = _b; } ~Test(){} ostream& operator<<(ostream &out) { out<<this->a<<", "<<this->b; return out; } }; void main() { Test st(10,20); st<<cout<<endl;//声明为成员函数则必须让对象在运算符前面,这样才能产生类似st.operator(out)的效果 }
效果如下
友元类
整个类可以是另一个类的友元。友元类得每个成员函数都是另一个类的友元函数,都可以访问另一个类中的保护
或私有数据成员
整个类可以是另一个类的友元。友元类得每个成员函数都是另一个类的友元函数,都可以访问另一个类中的保护
或私有数据成员
不积小流无以成江河