摄影网站建设目的,永久云服务器免费领,个人网站可以做电商吗,长沙网站优化页面友元
可以通过friend关键字#xff0c;把一个全局函数、另一个类的成员函数或者另一个类整体#xff0c;声明为授权类的友元友元拥有访问授权类任何非公有成员的特权友元声明可以出现在授权类的公有、私有或者保护等任何区域且不受访问控制限定符的约束友元不是成员#xf…友元
可以通过friend关键字把一个全局函数、另一个类的成员函数或者另一个类整体声明为授权类的友元友元拥有访问授权类任何非公有成员的特权友元声明可以出现在授权类的公有、私有或者保护等任何区域且不受访问控制限定符的约束友元不是成员其作用域并不隶属于授权类也不拥有授权类类型的this指针。
操作符标记和操作符函数
双目操作符表达式
L#R
成员函数形式L.operator#(R)
左操作数是调用对象右操作数是参数对象
全局函数形式operator#(L,R)
左操作数是第一个参数右操作数是第二个参数
单目操作符表达式
#O/O#
成员函数形式O.operator#()全局函数形式operator#(O)
三目操作符表达式 F#S#T
三目操作符无法重载
经典双目操作符
运算类双目操作符、-、*、/等
左右操作数均可以为非常左值、常左值或右值表达式的结果为右值
// 运算类双目操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}// 成员形式操作符函数
// Human operator(const Human r) const {
// return Human(this-m_ager.m_age, (this-m_namer.m_name).c_str());
// }
private:int m_age;string m_name;friend Human operator(const Human l,const Human r); // 友元声明
};
// 全局形式操作符函数
Human operator(const Human l, const Human r){return Human(l.m_ager.m_age, (l.m_namer.m_name).c_str());
}int main(void){Human a(22,张飞), b(20,赵云); // 非常左值const Human c(25,关羽), d(32,马超); // 常左值Human res a b; // a.operator(b) 或 operator(a,b)res.getInfo();res c d; // c.operator(d) 或 operator(c,d)res.getInfo();res Human(45,黄忠) Human(35,刘备); // Human(45,黄忠).operator(Human(35,刘备)) 或 // operator(Human(45,黄忠),Human(35,刘备))res.getInfo();return 0;
}
赋值类双目操作符、、-、*、/等
右操作数可以为非常左值、常左值或右值但左操作数必须为非常左值表达式结果为左操作数本身(而非副本)
// 赋值类双目操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}// 成员形式操作符函数Human operator(const Human r){this-m_age this-m_age r.m_age;this-m_name this-m_name r.m_name;return *this;}
private:int m_age;string m_name;friend Human operator(const Human l,const Human r); // 友元声明
};全局形式操作符函数
//Human operator(Human l, const Human r){
// l-m_age l-m_age r.m_age;
// l-m_name l-m_name r.m_name;
// return *l;
//}int main(void){Human a(22,张飞), b(20,赵云); // 非常左值const Human c(25,关羽), d(32,马超); // 常左值((ab)c)Human(45,黄忠);a.getInfo();return 0;
}
比较类双目操作符、、、、等
左右操作数为非常左值、常左值或右值表达式结果为 bool
// 比较类双目操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}
// // 成员形式操作符函数
// bool operator(/*const Human* this */ const Human that)const{
// return this-m_agethat.m_age this-m_namethat.m_name;
// }
// bool operator!(/*const Human* this */ const Human that)const{return this-m_age!that.m_age || this-m_name!that.m_name;
// return !(*thisthat);//使用operator
// }
private:int m_age;string m_name;friend bool operator(const Human l, const Human r); // 友元声明friend bool operator!(const Human l, const Human r); // 友元声明
};
// 全局形式操作符函数
bool operator(const Human l, const Human r){return l.m_ager.m_age l.m_namer.m_name;
}
bool operator!(const Human l, const Human r){
// return l.m_age!r.m_age || l.m_name!r.m_name;return !(lr);//使用operator
}int main(void){Human a(22,张飞), b(20,赵云); // 非常左值const Human c(25,关羽), d(32,马超); // 常左值cout (a b) endl; //0 a.operator(b) 或者 ...cout (a ! b) endl; //1 a.operator!(b) 或者 ...cout (c d) endl; //0 c.operator(d) 或者 ...cout (c ! d) endl; //1 c.operator!(d) 或者 ...cout (Human(45,黄忠) Human(35,刘备)) endl; //0 Human(45,黄忠).operator(Human(35,刘备)) 或者 ...cout (Human(45,黄忠) ! Human(35,刘备)) endl; //1 Human(45,黄忠).operator!(Human(35,刘备)) 或者 ...return 0;
}
经典单目操作符
运算类单目操作符:-、~、!等
操作数为非常左值、常左值或右值表达式的结果为右值
// 运算类单目操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}// 成员形式操作符函数Human operator-(/* const Human* this */)const{return Human(-this-m_age,(-this-m_name).c_str());}
private:int m_age;string m_name;
// friend Human operator-(const Human l); // 友元声明
};//Human operator-(const Human l){
// return Human(-l.m_age,(-l.m_name).c_str());
//}
int main(void){Human a(22,张飞), b(20,赵云); // 非常左值const Human c(25,关羽), d(32,马超); // 常左值Human res -a; // a.operator-() 或 ...res.getInfo();//姓名:-张飞, 年龄:-22res -c; // c.operator-() 或 ...res.getInfo();//姓名:-关羽, 年龄:-25res -Human(45,黄忠); // Human(45,黄忠).operator-() 或 ...res.getInfo();//姓名:-黄忠, 年龄:-45return 0;
}
前自增减类单目操作符: 前、前–
操作数为非常左值表达式的结果为操作数本身(而非副本
后自增减类单目操作符: 后 、后–
操作数为非常左值表达式的结果为右值且为自增减以前的值
// 自增减类单目操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}//成员形式操作符函数
// // 前 a
// Human operator(/* Human* this */){
// this-m_age1; // 直接加1
// this-m_namea; // 直接加
// return *this;
// }后 a
// Human operator(/* Human* this */int){
// Human old *this; // 备份原来的值
// this-m_age1; // 直接加1
// this-m_namea; // 直接加
// return old; // 返回原来的值
// }
private:int m_age;string m_name;friend Human operator(Human l); // 友元声明friend Human operator(Human l,int); // 友元声明
};// 前 aHuman operator(Human l){l.m_age1; // 直接加1l.m_namea; // 直接加return l;}// 后 aHuman operator(Human l,int){Human old l; // 备份原来的值l.m_age1; // 直接加1l.m_namea; // 直接加return old; // 返回原来的值}int main(void){Human a(22,张飞), b(20,赵云); // 非常左值const Human c(25,关羽), d(32,马超); // 常左值//姓名:张飞a, 年龄:23(a).getInfo(); // a.operator() 或 ...//姓名:赵云, 年龄:20(/*|...|*/b).getInfo(); // b.operator(0) 或 ...//姓名:赵云a, 年龄:21b.getInfo();return 0;
}
其他操作符
输出操作符:
左操作数为非常左值形式的输出流(ostream)对象右操作数为左值或右值表达式的结果为左操作数本身(而非副本左操作数的类型为ostream若以成员函数形式重载该操作符就应将其定义为ostream类的成员该类为标准库提供无法添加新的成员因此只能以全局函数形式重载该操作符
ostream operator (ostream os, const RIGHT right) { ...}
// 输入/输出流操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}
/* void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}*/// 成员形式操作符函数
private:int m_age;string m_name;friend ostream operator(ostream os, const Human that);friend istream operator(istream is, Human that);
};
// 全局形式操作符函数
ostream operator(ostream os, const Human that){os 姓名 that.m_name , 年龄 that.m_age;return os;
}//istream operator(istream is, Human that){
// is that.m_name that.m_age;
// return is;
//}int main(void){Human a(22,张飞); // 非常左值const Human b(20,赵云); // 常左值cout a endl; // cout.operator(a) 或 operator(cout,a)cout b endl; // cout.operator(b) 或 operator(cout,b)cout Human(45,黄忠) endl; // cout.operator(Human(45,黄忠)) 或 operator(cout,Human(45,黄忠))// cin a; // cin.operator(a) 或 operator(cin,a)cout a endl;return 0;
}
输入操作符:
左操作数为非常左值形式的输入流(istream)对象右操作数为非常左值表达式的结果为左操作数本身(而非副本)左操作数的类型为istream若以成员函数形式重载该操作符,就应将其定义为istream类的成员该类为标准库提供无法添加新的成员因此只能以全局函数形式重载该操作符
istream operator (istream is, RIGHT right) { ...}
// 输入/输出流操作符函数
#include iostream
using namespace std;class Human{
public:Human(int age 0, const char* name匿名):m_age(age),m_name(name){// [int m_age age;]// [string m_name(name);]}
/* void getInfo(){cout 姓名: m_name , 年龄: m_age endl;}*/// 成员形式操作符函数
private:int m_age;string m_name;friend ostream operator(ostream os, const Human that);friend istream operator(istream is, Human that);
};
// 全局形式操作符函数
ostream operator(ostream os, const Human that){os 姓名 that.m_name , 年龄 that.m_age;return os;
}istream operator(istream is, Human that){is that.m_name that.m_age;return is;
}int main(void){Human a(22,张飞); // 非常左值cin a; // cin.operator(a) 或 operator(cin,a)cout a endl;return 0;
}
下标操作符:[]
一般用于在容器类型中以下标方式获取数据元素非常容器的元素为非常左值常容器的元素为常左值
类型转换操作符
若源类型是基本类型目标类型是类类型则只能通过类型转换构造函数实现自定义类型转换
class 目标类型{目标类型(const 源类型 src){ ... }
}若源类型是类类型目标类型是基本类型则只能通过类型转换操作符函数 实现自定义类型转换
class 源类型{operator 目标类型(void) const { ...}
}若源类型和目标类型都是类类型 (而非基本类型) 则既可以通过类型转换构造函数也可以通过类型转换操作符函数实现自定义类型转换但不要两者同时使用
若源类型和目标类型都是基本类型则无法实现自定义类型转换基本类型间的类型转换规则完全由编译器内置
类型转换构造函数和类型转换操作符函数
// 类型转换构造函数和类型转换操作符函数
#include iostream
using namespace std;class Integer{
public:Integer(int i):m_i(i){//【int m_i i;】cout Integer类的类型转换构造函数被调用 endl;}operator int(/* const Integer* this */)const{cout Integer类的类型转换操作符函数被调用 endl;return this-m_i;}
private:int m_i;
};int main(void){int n 666;// int -- Integer(基本类型--类类型)Integer ix n; // 定义匿名Integer对象利用匿名Integer对象.Integer(n) -- 触发类型转换构造函数// Integer ix n.operator Integer() -- int类中没有一个operator Integer(走不通) // Integer -- int(类类型 -- 基本类型)int m ix; // 定义匿名int对象利用匿名int对象.int(ix)--int类中没有一个形参是Integer类型的构造函数(走不通)// int m ix.operator int() -- 触发类型转换操作符函数return 0;
}
// 类型转换构造函数和类型转换操作符函数
#include iostream
using namespace std;class Dog; // 短式声明/前置声明class Cat{
public:Cat(const char* name):m_name(name){// [string m_name(name);]}void talk() {cout m_name : 喵喵~~~ endl;}operator Dog(/* const Cat* this */)const; // 声明
private:string m_name;friend class Dog; // 友元声明
};class Dog{
public:Dog(const char* name):m_name(name){// [string m_namename;]}
/* Dog(const Cat that):m_name(that.m_name){ // 类型转换构造(定制了Cat--Dog的转换规则)//【string m_name that.m_name;】cout Dog类的类型转换构造函数被调用 endl;}*/void talk() {cout m_name : 汪汪~~~ endl;}
private:string m_name;
};
Cat::operator Dog(/* const Cat* this */)const{ // 定义cout Cat类的类型转换操作符函数被调用 endl;return Dog(this-m_name.c_str());
}int main( void ) {Cat smallwhite(小白); Dog bigyellow smallwhite; // 定义匿名Dog类对象利用匿名Dog类对象.Dog(smallwhite)--触发Dog类的类型转换构造函数// Dog bigyellow smallwhite.operator Dog() -- 触发Cat类的类型转换操作符函数return 0;
}
操作符重载的局限
不是所有的操作符都能重载以下操作符不能重载
作用域限定操作符(::)直接成员访问操作符(.)条件操作符(?:)字节长度操作符(sizeof)类型信息操作符(typeid)
无法重载所有操作数均为基本类型的操作符: 如实现 113
c的前和后
在C语言中 前: 先加1再使用 a 后: 先使用再加1 a在C语言中不管是前还是后都是直接加1内部原理和C语言并不同 但是C希望用户感觉和C一样
c的前和后的区别
表达式方式区别i是先取变量i再将变量i值1而i是先将变量i值1再取变量i。在循环遍历容器变量时这两种方式的结果都是一样的但是本质的效率上有很大的区别下面介绍另一种效率区别。效率两种方式iterator遍历的次数是相同的但在STL中效率不同前返回引用后返回一个临时对象因为iterator是类模板使用 it这种形式要返回一个无用的临时对象而it是函数重载所以编译器无法对其进行优化所以每遍历一个元素你就创建并销毁了一个无用的临时对象。C的标准库还有符合标准C的教材除了特殊需要和对内置类型外基本都是使用it来进行元素遍历的不管是源代码还是教材中都是如此。
下面是标准库源码