1)

请问类中函数 const修饰的谁

把类中的成员函数 转换成全局函数

成员函数返回*this


2)

自定义数组类封装 申明 与实现分开写 具有以下函数

void arr_set(int n,int value);

int arr_get(int n);

int arr_len()


3)

为什么会有友元函数

友元类:


4)

运算符重载

可以进行运算符重载的符


【二元操作符】 + -

全局函数的运算符重载,private成员变量

成员函数的运算符重载,private成员变量


【一元运算符】

成员函数,全局函数

前置++ 后置++

前置-- 后置--


有元函数的正真使用场景:

返回引用类型,链式输出对象的信息




5)

【难点】运算符重载提高

等号=

中括号[],当左值,当右值

相等符号 ==

不等于 !=


6)作业:封装一个字符类,使用 << ,>>,!= ,==,=,

附:运算符结合方向:




1,请问类中函数 const修饰的谁?

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{public://const的三种写法//constvoidfun(inta,intb)//voidconstfun(inta,intb)//voidfun(inta,intb)constvoidfun(inta,intb)const{a=100;//const修饰的不是a//this->a=200;//编译提示:‘A::a’inread-onlyobject}private:inta;intb;};intmain(){Aa1;return0;}


答案:

const的三种写法修饰的是this指针

const void fun(int a,int b)

void const fun(int a,int b)

void fun(int a,int b) const

this指针所指向的内存空间不能被修改

相当于 void fun(const A *this,int a,int b)

修改this指针本身的值,编译也不通过




把类中的成员函数 转换成全局函数

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{public:voidfun(){cout<<"a="<<this->a<<"b="<<this->b<<"infun"<<endl;}A(inta=0,intb=0){this->a=a;this->b=b;cout<<"a="<<this->a<<"b="<<this->b<<"ininit\n";}Aadd(A&a){At(this->a+a.a,this->b+a.b);returnt;}A(constA&obj){cout<<"incopy\n";}~A(){cout<<"a="<<a<<"b="<<b<<"free\n";}public:inta;intb;};//把成员函数转成全局函数Afun(A&a1,A&a2){Aa3;returna3;}voidfun1(){cout<<"--------infun1-------------------\n";Aa1(1,2);Aa2(3,4);Aa3=a1.add(a2);a3.fun();}voidfun2(){cout<<"--------infun2-------------------\n";Aa1(1,2);Aa2(3,4);Aa3(5,5);a3=a1.add(a2);a3.fun();}intmain(){fun1();fun2();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out--------infun1-------------------a=1b=2ininita=3b=4ininita=4b=6ininita=4b=6infuna=4b=6freea=3b=4freea=1b=2free--------infun2-------------------a=1b=2ininita=3b=4ininita=5b=5ininita=4b=6ininita=4b=6freea=4b=6infuna=4b=6freea=3b=4freea=1b=2free



成员函数返回*this

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{public:voidfun(){cout<<"a="<<this->a<<"b="<<this->b<<"inprint"<<endl;}A(inta=0,intb=0){this->a=a;this->b=b;cout<<"a="<<this->a<<"b="<<this->b<<"ininit\n";}//返回一个引用,相当于返回自身A&add(A&a){this->a+=a.a,this->b+=a.b;return*this;}A(constA&obj){cout<<"incopy\n";}~A(){cout<<"a="<<a<<"b="<<b<<"free\n";}public:inta;intb;};intmain(){Aa1(1,2);Aa2(3,4);a1.add(a2);a1.fun();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.outa=1b=2ininita=3b=4ininita=4b=6inprinta=3b=4freea=4b=6freechunli@Linux:~/c++$




自定义数组类封装 具有以下函数

void arr_set(int n,int value);

int arr_get(int n);

int arr_len();

文件1:

chunli@Linux:~/c++$catmy_arr.h#pragmaonceclassArr{public:voidarr_set(intn,intvalue);intarr_get(intn);intarr_len();Arr(intn);Arr(constArr&boj);~Arr();private:intlen;int*arr;};chunli@Linux:~/c++$

文件2:

chunli@Linux:~/c++$catmy_arr.cpp#include"my_arr.h"#include<iostream>usingnamespacestd;voidArr::arr_set(intn,intvalue){this->arr[n]=value;}intArr::arr_get(intn){returnthis->arr[n];}intArr::arr_len(){returnthis->len;}Arr::Arr(intn){if(n<1){len=0;arr=NULL;}else{this->len=n;arr=newint[n];cout<<n<<"init...\n";}}Arr::Arr(constArr&obj){this->len=obj.len;arr=newint[this->len];for(inti=0;i<this->len;i++){this->arr[i]=obj.arr[i]+1;}cout<<this->len<<"copy...\n";}Arr::~Arr(){if(arr!=NULL){cout<<this->len<<"free...\n";delete[]arr;len=0;}}chunli@Linux:~/c++$

文件3:

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include"my_arr.h"#include<stdlib.h>usingnamespacestd;intmain(){Arra1(20);for(inti=0;i<a1.arr_len();i++){a1.arr_set(i,i);}for(inti=0;i<a1.arr_len();i++){cout<<a1.arr_get(i)<<"";}cout<<endl;Arra2=a1;//等号操作,C++编译器会调用拷贝构造函数for(inti=0;i<a2.arr_len();i++){cout<<a2.arr_get(i)<<"";}cout<<endl;return0;}

编译运行:

chunli@Linux:~/c++$g++-gmain.cppmy_arr.cpp&&./a.out20init...01234567891011121314151617181920copy...123456789101112131415161718192020free...20free...chunli@Linux:~/c++$







为什么会有友元函数?


在实现类之间数据共享时,减少系统开销,提高效率。

如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数。

具体来说:为了使其他类的成员函数直接访问该类的私有变量。

即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数。


实际上具体大概有下面两种情况需要使用友元函数:

(1)运算符重载的某些场合需要使用友元。

(2)两个类要共享数据的时候。

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{public:A(inta,intb){this->a=a;this->b=b;}private:inta;intb;};voidfun(A*p){//不能在类的外部访问私有属性intn=p->a;}intmain(){Aa1(1,2);fun(&a1);return0;}编译就报错:chunli@Linux:~/c++$g++-gmain.cpp&&./a.outmain.cpp:Infunction‘voidfun(A*)’:main.cpp:13:6:error:‘intA::a’isprivateinta;^


把这个函数添加为友元函数就OK了

友元函数 与 位置没有关系

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{friendvoidfun(A*p);public:A(inta,intb){this->a=a;this->b=b;}intget_a(){returnthis->a;}private:inta;intb;};voidfun(A*p){//不能在类的外部访问私有属性p->a=10;intn=p->a;cout<<n<<endl;}intmain(){Aa1(1,2);fun(&a1);cout<<a1.get_a()<<endl;return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out1010


友元类:

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{friendclassB;private:inta;};classB{friendvoidfun(A*p);public:B(inta){a1.a=a;//可以直接修改友元类的属性}intget_a(){returnthis->a1.a;////可以直接修改友元类的属性}private:inta;Aa1;};intmain(){Bb1(11);cout<<b1.get_a()<<"\n";return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out11chunli@Linux:~/c++$



运算符重载,初步

让两个类直接相加减



运算符重载本质是一个函数

约定operator关键字

C++编译器会自动去找运算符


chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>usingnamespacestd;classA{public:A(inta,intb){this->a=a;this->b=b;}intprintf(){cout<<a<<""<<b<<endl;}inta;intb;};Aoperator+(A&a,A&b){cout<<"HelloWorld\n";At(a.a+b.a,a.b+b.b);returnt;}intmain(){Aa1(1,1);Aa2(2,2);Aa3=a1+a2;a3.printf();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.outHelloWorld33chunli@Linux:~/c++$


可以进行运算符重载的符合

不可以进行运算符重载的符合




【二元操作符】成员函数的运算符重载

此时的成员变量还都是public的

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{public:Aoperator+(Aobj){cout<<"成员函数的运算符重载\n";At(this->a+obj.a+1,this->b+obj.b+1);returnt;}A(inta,intb){this->a=a;this->b=b;}intprintf(){cout<<a<<""<<b<<endl;}inta;intb;};intmain(){Aa1(1,1);Aa2(2,2);Aa3=a1+a2;a3.printf();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out成员函数的运算符重载44



【二元操作符】全局函数的运算符重载

此时的成员变量都是private的

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{friendAoperator+(A&a,A&b);public:A(inta,intb){this->a=a;this->b=b;}intprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};Aoperator+(A&a,A&b){cout<<"HelloWorld\n";At(a.a+b.a,a.b+b.b);returnt;}intmain(){Aa1(1,1);Aa2(2,2);Aa3=a1+a2;a3.printf();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.outHelloWorld33





【二元操作符】成员函数的运算符重载

此时的成员变量都是private的

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{public:Aoperator+(Aobj){cout<<"成员函数的运算符重载\n";At(this->a+obj.a+1,this->b+obj.b+1);returnt;}A(inta,intb){this->a=a;this->b=b;}intprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};intmain(){Aa1(1,1);Aa2(2,2);Aa3=a1+a2;a3.printf();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out成员函数的运算符重载44


【一元运算符】前置++

全局函数 运算符重载

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{friendA&operator++(A&a);public:A(inta,intb){this->a=a;this->b=b;}intprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};A&operator++(A&a){cout<<"成员函数的运算符重载\n";a.a++;a.b++;returna;}intmain(){Aa1(1,1);++a1;a1.printf();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out成员函数的运算符重载22



【一元运算符】前置++

成员函数 运算符重载

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{public:A&operator++(){cout<<"成员函数的运算符重载\n";this->a++;this->b++;return*this;//A&需要返回一个实体,而不是指针}A(inta,intb){this->a=a;this->b=b;}intprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};intmain(){Aa1(1,1);++a1;a1.printf();return0;}chunli@Linux:~/c++$g++-gmain.cpp&&./a.out成员函数的运算符重载22chunli@Linux:~/c++$



全局函数 成员函数

前置++ 后置++

前置-- 后置--

【注意】全局函数的声明 要与友元函数的声明一致

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{friendA&operator--(A&a);friendAoperator--(A&a,int);public:A&operator++(){cout<<"前置++一元运算符重载";this->a++;this->b++;return*this;//A&需要返回一个实体,而不是指针}Aoperator++(int){cout<<"后置++一元运算符重载";At=*this;this->a++;this->b++;returnt;}A(inta,intb){this->a=a;this->b=b;}voidprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};A&operator--(A&t){cout<<"前置--一元运算符重载";t.a--;t.b--;returnt;}Aoperator--(A&from,int){cout<<"后置--一元运算符重载";At(from);from.a--;from.b--;returnt;}intmain(){Aaa(5,6);Aa1(aa++);a1.printf();Aab(5,6);Aa2(++ab);a2.printf();Aac(5,6);Aa3(ac--);a3.printf();Aad(5,6);Aa4(--ad);a4.printf();return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.out后置++一元运算符重载56前置++一元运算符重载67后置--一元运算符重载56前置--一元运算符重载45chunli@Linux:~/c++$




有元函数的正真使用场景:

使用cout输出一个自定义类的成员变量,必须修改ostream类源码

在拿不到iostream的源代码的情景下,只能使用友元函数

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{friendvoidoperator<<(ostream&friend_ship,A&from);public:A(inta,intb){this->a=a;this->b=b;}voidprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};voidoperator<<(ostream&friend_ship,A&from){friend_ship<<"友元函数的真正应用场景\n";friend_ship<<from.a<<""<<from.b<<endl;}intmain(){Aa(5,6);cout<<a;return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.out友元函数的真正应用场景56


链式输出对象的信息 cout << a << a;

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classA{friendostream&operator<<(ostream&friend_ship,A&from);public:A(inta,intb){this->a=a;this->b=b;}voidprintf(){cout<<a<<""<<b<<endl;}private:inta;intb;};//链式输出需要返回一个引用//<<操作符是至左向右结合ostream&operator<<(ostream&friend_ship,A&from){friend_ship<<"友元函数的真正应用场景\n";friend_ship<<from.a<<""<<from.b<<endl;returnfriend_ship;}intmain(){Aa(5,6);cout<<a<<a;return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.out友元函数的真正应用场景56友元函数的真正应用场景56




运算符重载提高:1

等号 = 运算符重载: 支持链式操作

【难点】 释放之前的指针,返回一个引用

chunli@Linux:~/c++$catmain.cpp#include<iostream>#include<stdlib.h>#include<string.h>usingnamespacestd;classStr{public:Str(constchar*p){this->len=strlen(p);this->p=(char*)malloc(this->len+1);strcpy(this->p,p);this->p[len]='\0';cout<<this->p<<"init\n";}Str(constStr&from){this->len=strlen(from.p);this->p=(char*)malloc(this->len+1);strcpy(this->p,from.p);this->p[this->len]='\0';cout<<"incopy\n";}~Str(){if(this->p!=NULL){cout<<this->p<<"free\n";free(this->p);this->p=NULL;this->len=0;}}Str&operator=(Str&from){if(this->p!=NULL){free(this->p);//先把自己之前的指针释放掉}cout<<from.p<<"->in=operator\n";this->len=strlen(from.p);this->p=(char*)malloc(this->len+1);strcpy(this->p,from.p);this->p[len]='\0';return*this;}private:char*p;intlen;};intmain(){Strs1("Hello");Strs2("Linux");Strs3("Google");s1=s2=s3;//对象的赋值操作s1=s2,不会调用赋值构造函数return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.outHelloinitLinuxinitGoogleinitGoogle->in=operatorGoogle->in=operatorGooglefreeGooglefreeGooglefree



中括号[]运算符重载,数组类的

【难点】:函数当右值,函数当左值

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classArr{public:Arr(intn){this->len=n;p=newint[n];}~Arr(){delete[]p;}int&operator[](inti){returnp[i];}intlen;int*p;};intmain(){Arra1(16);for(inti=0;i<a1.len;i++){a1[i]=i*i;}for(inti=0;i<a1.len;i++){cout<<a1[i]<<"";}cout<<"\n";return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.out0149162536496481100121144169196225




【强化数组类练习!】等号=运算符重载,中括号[]运算符重载

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classArr{public:Arr(intn){this->len=n;p=newint[n];}~Arr(){if(p!=NULL){delete[]p;p=NULL;}}int&operator[](inti){returnp[i];}Arr&operator=(Arr&from){if(this->p!=NULL){delete[]p;}this->len=from.len;this->p=newint[this->len];for(inti=0;i<from.len;i++){this->p[i]=from.p[i];}return*this;}voidout(){for(inti=0;i<this->len;i++){cout<<this->p[i]<<"\t";}cout<<"\n";}voidinit(intnum){for(inti=0;i<this->len;i++){this->p[i]=i+num;}}intlen;int*p;};intmain(){Arra1(16);a1.init(1);a1.out();Arra2(10);a2.init(2);a2.out();a1=a2;a1.out();return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.out12345678910111213141516234567891011234567891011



数组的 相等== 运算操作符重载,不等于!= 操作符重载

chunli@Linux:~/c++$catmain.cpp#include<iostream>usingnamespacestd;classArr{public:Arr(intn){this->len=n;p=newint[n];}~Arr(){if(p!=NULL){delete[]p;p=NULL;}}int&operator[](inti){returnp[i];}Arr&operator=(Arr&from){if(this->p!=NULL){delete[]p;}this->len=from.len;this->p=newint[this->len];for(inti=0;i<from.len;i++){this->p[i]=from.p[i];}return*this;}booloperator!=(Arr&from){if(this->len!=from.len){returntrue;}for(inti=0;i<from.len;i++){if(this->p[i]!=from.p[i]){returntrue;}}returnfalse;}booloperator==(Arr&from){if(this->len!=from.len){returnfalse;}for(inti=0;i<from.len;i++){if(this->p[i]!=from.p[i]){returnfalse;}}returntrue;}voidout(){for(inti=0;i<this->len;i++){cout<<this->p[i]<<"\t";}cout<<"\n";}voidinit(intnum){for(inti=0;i<this->len;i++){this->p[i]=i+num;}}intlen;int*p;};intmain(){Arra1(16);a1.init(1);a1.out();Arra2(10);a2.init(2);a2.out();a1=a2;a1.out();Arra3(10);a3.init(1);Arra4(10);a4.init(1);if(a3==a4){cout<<"a3==a4\n";}else{cout<<"a3!=a4\n";}a4.init(2);//修改a4数组的值if(a3!=a4){cout<<"a3!=a4\n";}else{cout<<"a3==a4\n";}return0;}chunli@Linux:~/c++$g++-Wall-gmain.cpp&&./a.out12345678910111213141516234567891011234567891011a3==a4a3!=a4



运算符结合方向: