《运算符重载》PPT课件.ppt_第1页
《运算符重载》PPT课件.ppt_第2页
《运算符重载》PPT课件.ppt_第3页
《运算符重载》PPT课件.ppt_第4页
《运算符重载》PPT课件.ppt_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1,第十八章 运算符重载,2,本章主要内容,运算符重载的需要性 重载运算符作友元函数 运算符作成员函数 增量运算符重载 转换运算符重载 赋值运算符重载,3,C+认为用户定义的数据类型就像基本数据类型int和char一样有效。运算符(如+, -,*,/)是为基本数据类型定义的,为什么不允许使之适用于用户定义类型呢?例如: class A public: A(int x) a=x; / ; A a(5),b(10),c; c=a+b; /类对象也应能运算 运算符重载可以改进可读性,但不是非有不可。,4,多态性的实现: 函数重载 虚函数 运算符重载 在基本类型上,系统提供了许多预定义的运算符(如+、-、*、/)。,5,问题举例复数的运算,class complex /复数类声明 public: complex(double r=0.0,double i=0.0)real=r;imag=i; void display(); /显示复数的值 private: double real; double imag; ;,用“+”、“-”能够实现复数的加减运算吗? 实现复数加减运算的方法 重载“+”、“-”运算符 必要性 C+中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)。 运算符重载可提高程序的可读性。,下列例子计算应付给的人民币,分别用了成员函数和运算符成员函数两种方法 class RMB public: RMB(double d)yuan=d; jf=(d-yuan)/100; RMB interest(double rate); /计算利息 RMB add(rmb d); /人民币加 RMB operator + (RMB d) /人民币加的运算符重载 return RMB(yuan+d.yuan+(jf+d.jf)/100; RMB operator * (double rate) return RMB(yuan+jf/100)*rate); private: unsigned int yuan; / 元 unsigned int jf; / 角分 ;,RMB RMB:interest(double rate) return RMB(yuan+jf)/100.0) * rate); RMB RMB:add(RMB d) return RMB(yuan+d.yuan+jf/100.0+d.jf/100.0); /以下是计算应付人民币的两个版本 RMB expense1(RMB principle,double rate) RMB interest = erest(rate); return principle.add(interest); RMB expense2(RMB principle,double rate) RMB interest = principle * rate; return principle + interest; ,9,void main() RMB x = 10000.0; double yrate = 0.035; expense1(x,yrate).display(); expense2(x,yrate).display(); 运行结果为: 20350 10350 expense()的两个版本都可以计算应付人民币,运行结果相同。expense2()可读性更好一点,它符合我们计算用+, *运算符的习惯。 如果不定义运算符重载,则expense2()中principal * rate和principal+interest是非法的。因为参加运算的是类对象而不是浮点值。,10,运算符重载的实质,运算符重载是对已有的运算符赋予多重含义。 实现机制 运算符重载的实质就是函数重载:每个运算符对应各自的运算符函数,根据操作数的不同调用不同的同名函数。 将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。,11,规则和限制,编译系统对重载运算符的选择,遵循函数重载的选择原则。 可以重载C+中除下列运算符外的所有运算符: . .* . : ?: 只能重载C+语言中已有的运算符,不可臆造新的。 不改变原运算符的优先级和结合性。 不能改变操作数个数。 经重载的运算符,其操作数中至少应该有一个是自定义类的对象或是对类的对象的引用。,12,运算符重载的两种形式,重载为类的友元函数: friend 类型 operator 运算符(形参表) 函数体 重载为类的成员函数: 类型 operator 运算符(形参表) 函数体 ,13,如何重载运算符,运算符是在C+系统内部定义的,具有特定语法规则,如参数说明,运算顺序,优先级等。重载运算符时,要注意该重载运算符的运算顺序和优先级不变,14,class A public: A(int n) / operator +(Aa,A&) / operator *(Aa,AA) / / ;,15,A a = 5,b = 6, c = 7,d= 8, e; e = a + b * c + d;/即 ( a + (b * c ) ) + d 有了运算符,编程就显得方便。例如,对于直角三角形斜边长度公式c= 用函数化的格式表示: c=sqrt(add(mult (a,a),mult(b,b) ) ); 用运算符的格式表示: c=sqrt(a * a + b * b);,16,运算符是函数,除了运算顺序和优先级不能更改外,参数和返回类型是可以重新说明的,即可以重载。重载的形式是: 返回类型operator运算符号(参数说明),17,例如:A类对象加法: class A; int operator +(A/两个A类对象参加运算,返回int型值 C+规定,运算符中,参数说明都是内部类型时,不能重载。例如不允许声明: int* operator+(int,int*); 即不允许进行下述运算: int a=5; int* pa=&a; pa=a*pa; error C+基本数据类型之间的关系是确定的,如果允许定义其上的新操作 ,那么,基本数据类型的内在关系将混乱。,18,C+还规定了“、: 、* 、-、?:”这五个运算符不能重载,也不能创造新运算符。 例如,不允许声明: int operator (int,int); 或者: int operator:(int,int);,19,本章主要内容,运算符重载的需要性 重载运算符作友元函数 运算符作成员函数 增量运算符重载 转换运算符重载 赋值运算符重载,20,如果需要重载一个运算符,使之能够用于操作某类对象的私有成员,可以此将运算符重载为该类的友元函数。 重载为友元函数时 参数个数=原操作数个数,且至少应该有一个自定义类型的形参。 友元函数是类以外的函数,调用这种运算符函数时,所有的操作数都要通过参数传递来获得。,运算符友元函数的设计,21,例一:,将+、-(双目)重载为复数类的友元函数。 规则: 实部和虚部分别相加减。 两个操作数都是复数类的对象。,#include class complex public: complex(double r=0.0,double i=0.0) real=r; imag=i; friend complex operator + (complex c1,complex c2); /运算符+重载为友元函数 friend complex operator - (complex c1,complex c2); /运算符-重载为友元函数 void display(); /显示复数的值 private: double real; double imag; ;,complex operator +(complex c1,complex c2) /运算符重载友元函数实现 return complex(c2.real+c1.real, c2.imag+c1.imag); complex operator -(complex c1,complex c2) /运算符重载友元函数实现 return complex(c1.real-c2.real, c1.imag-c2.imag); void complex:display() cout“real:“real“ imag:“imagendl; ,void main() complex c1(4.6,6.5), c2(3.9,1.4),c3,c4; c3=operator +(c1,c2); c3.display(); /c3 = c1 + c2 ; complex c4=c1+c2; / c3.display();,25,Vc6中 #include “iostream“ using namespace std; 会后fatal error C1001: INTERNAL 错误COMPILER ERROR 用dev-c+能顺利通过,例二:程序将运算符+和+声明为人民币类的友元: class RMB public: RMB(unsigned int d,unsigned int c); friend RMB operator + (RMB,RMB operator +(RMB ,28,RMB:RMB(unsigned int d, unsigned int c) yuan = d; jf = c; while ( jf =100 ) /以使构造时,确保角分值小于100yuan +; jf -= 100; ,void main() RMB d1(2,48); RMB d2(3,28); RMB d3(0,0); d3 = d1 + d2; +d3; d3.display(); ,问题一: 为什么operator +( )中的参数用引用传递而不用指针传递? 问题二: 为什么operator +( )由值返回,而operator +( )由引用返回?,30,operator+()和operator+()定义为友元是为了能访问人民币类的保护成员。 operator+()是一个双目运算符,它有两个参数s1和s2,并且相加的结果仍为人民币类,返回人民币类对象。,31,注意: 不是必须要让operator+()执行加法,可以让它做任何事。但是不让它做加法,而做其他操作是一个很糟的想法。如果重载+运算符,向一个磁盘文件写10次“I like C+”,语法上可以,但与语义相差悬殊,不利于可读性,背离了允许运算符重载的初衷。当别人读这个程序时,发现s1+s2的操作,想象是某种加法操作,怎么也想不到会是这样的写操作:所以在使重载运算符脱离原义之前,必须保证有充分的理由。,32,-为什么operator+()中的参数用引用传递而不用指针传递? 因为指针传递存在程序上的可读性问题:如果操作符重载声明为: RMB operator+(RMB* a,RMB* b); 则调用时, RMB s1(5.1); RMB s2(6.7); RMB c=&sl+&s2;/是s1的地址与s2的地址相加吗? operator+()是单目运算符,它含有一个参数。operator+()对人民币类对象的角分做加1运算,如果它超过100,则对该对象的元做加1运算并使角分为0(减100)。 如果只给出一个operator+()定义,那么它一般可用于前缀后缀两种形式。即d3+与+d3不作区别。,33,值返回与引用返回,上节中,为什么operator+()由值返回,而operator+()由引用返回呢? 重载定义+和+操作的意义是人为的,所以返回类型并非一定如此规定。但如上节定义的+和+操作的意义,应该规定+由值返回,+由引用返回。 对于operator+(),两个对象相加,不改变其中任一个对象。而且它必须生成一个结果 对象来存放加法的结果,并将该结果对象以值的方式返回给调用者。,34,如果+以引用返回如下例: RMB& operator +(RMB& s1,RMB& s2) unsigned int jfs1.jf+s2.jf; unsigned int yuan=s1.yuan+s2.yuan; RMB result(yuan,Jf); return result; 则尽管编译正确,能够运行,但会产生奇怪的结果。例中的result对象由+运算符函数的栈空间分配内存,受限于块作用域,引用返回导致了调用者使用这块会被随时分配的空间,35,能否将结果对象从堆中分配来避免上例的问题呢?例如: RMB 虽然它无编译问题,可以运行,但是该堆空间无法回收,因为没有指向该堆空间的指针,会导致内存泄漏,程序不断做加法时,堆空间也在不断流失。,36,如果坚持结果对象从堆中分配,而返回一个指针,那样在应用程序中就要付出代价: void fn(RMB”,则a+b的临时对象赋给c,然后临时对象的作用域也结束了。,37,与operator+()不一样,operator+()确实修改了它的参数,而且其返回值要求是左值,这个条件决定了它不能以值返回。如果以值返回: RMB operator +(RMB /ok,a为2.52,38,本章主要内容,运算符重载的需要性 重载运算符作友元函数 运算符作成员函数 增量运算符重载 转换运算符重载 赋值运算符重载 New和delete运算符重载,重载为类成员函数时 参数个数=原操作数个数-1 (后置+、-除外) 作为成员的运算符比之作为非成员的运算符,在声明和定义时,形式上少一个参数。这是由于C+对所有的成员函数隐藏了第一个参数this。 C+规定:=,(), ,-这4种运算符必须为成员函数。,40,例一:,将“+”、“-”运算重载为复数类的成员函数。 操作数: 两个操作数都是复数类的对象。 一个运算符除了可以作为一个非成员函数实现外,还可以作为一个成员函数实现,#include class complex public: complex(double r=0.0,double i=0.0)real=r;imag=i; complex operator + (complex c2); /+重载为成员函数 complex operator - (complex c2); /-重载为成员函数 void display(); /输出复数 private: double real; /复数实部 double imag; /复数虚部 ;,/重载运算符函数的实现 complex complex:operator +(complex c2) complex c; c.real=c2.real+real; c.imag=c2.imag+imag; return complex(c.real,c.imag); ,/重载运算符 - 函数实现 complex complex:operator - (complex c2) complex c; c.real=real-c2.real; c.imag=imag-c2.imag; return complex(c.real,c.imag); ,void complex:display() cout“(“real“,“imag“)“endl; void main() /主函数 complex c1(5,4),c2(2,10),c3; /定义复数类的对象 cout“c1=“; c1.display(); cout“c2=“; c2.display(); c3=c1-c2; /使用重载运算符完成复数减法 cout“c3=c1-c2=“; c3.display(); c3=c1+c2; /使用重载运算符完成复数加法 cout“c3=c1+c2=“; c3.display(); ,程序输出的结果为: c1=(5,4) c2=(2,10) c3=c1-c2=(3,-6) c3=c1+c2=(7,14),例二: class RMB public: RMB(unsigned int d,unsigned int c); RMB operator + (RMB,RMB RMB:operator +(RMB ,48,RMB RMB:operator +(int c) RMB result(5,c); return result; RMB:RMB(unsigned int d, unsigned int c) yuan = d; jf = c; while(jf =100) yuan +; jf -= 100; ,void main() RMB d1(2,48); RMB d2(3,28); RMB d3(0,0); d3 = d1 + d2; / d3 = d1 +2; /d3 = 2 +d1;/error /d3=d1.operator +(d2); +d3; /d3.operator +(); d3.display(); ,问题:成员和友元运算符函数有区别吗?,50,从中看出,作为成员的运算符比之作为非成员的运算符,在声明和定义时,形式上少一个参数。这是由于C+对所有的成员函数隐藏了第一个参数this,51,RMB operator +(RMB& s1,RMB& s2) /非成员形式 unsigned int jf=s1.jf+s2.jf; unsigned int yuan =s1.yuan+s2.yuan; RMB result(yuan,jf); return result; RMB RMB:operator +(RMB& s) /成员形式 unsigned int c=jf+s.jf; unsigned int d=yuan+s.yuan; RMB result(c,d); return result; ,52,可见函数体中内容几乎相同,只是非成员形式加s1和s2,成员形式s加当前对象,当前对象的成员隐含着由this指向。即yuan意味着thisyuan。 一个运算符成员形式,将比非成员形式少一个参数,左边参数是隐含的。 作为人民币类的一种常规操作,我们应该允许其中有一个操作数是double型的情况: c=c+2.5; c=2.7+c;,53,RMB d3(0, 0); / d3=d1.operator +(d2); d3 = d1 +2; RMB RMB:operator +(int c) RMB result(5,c); return result; ,54,但是由于参数类型不同,上例的运算符不论是成员形式还是非成员形式,都不能被这两个调用所匹配,还必须重载下列两个成员运算符: RMB operator +(RMB& s,double d) unsigned int y=s.yuan+d; unsigned int j=s.jf+(d-(int)d)* 100+0.5; RMB result(y,j); inline RMB operator +(double d,RMB& s) return s+d; 这里第二个重载运算符调用了第一个重载运算符,两者之间只是参数顺序相反,定义后 者为内联函数是一个技巧,省去了必要的开销。,55,从中得出,为了适应其中一个操作数是double的情况,不得不额外引入两个重载运算符。如果有构造函数: RMB(double value) yuan=value; jf=(value-yuan)*100.0+0.5; 就能够将double通过构造,变换成RMB类,于是: , class RMB public: RMB(unsigned int d,unsigned int c); RMB(double value); friend RMB operator +(RMB& sl, RMB& s2); 其余同前 ;,56,void main() RMB s(5.8); s=RMB(1.5)+s;/显式转换(创建个无名对象) s=1.5+s;/隐式转换 s=s+1.5; /隐式转换 s=s+1;/将in仁变换成double,然后像上面那样变换 现在不必定义operator +(double,RMB&)和operator +(RMB&,double)了,因为可将double转换成RMB类,然后匹配operator +(RMB&,RMB&),57,该变换可以是显式的,如s=RMB(1.5)+s那样,也可以是隐含的。此时,由于其中的一个操作数是RMB对象,而且参数个数相同,所以它首先假定operator +(RMB&,RMB&)可以匹配,然后寻找能够使用的转换。发现构造函数RMB(double)可作为转换的依据。在完成转换后,真正匹配operator +(RMB&,RMB&)运算符。所以程序员可以通过定义转换函数,来减少定义的运算符个数。 但是如果是下面的情况: s=1.5+6.4; 那么由于左右操作数都是double型,所以匹配基本数据类型的加法,进行浮点运算。然后因为赋值表达式左面是RMB对象,所以该赋值运算将右面表达式的结果用构造函数RMB(double)进行RMB转换,再赋值给s。 C+规定:=,(),这四种运算符必须为成员形式。,58,在实现加法运算符时,用的是非成员形式。如果将运算符改成成员形式,那么,对于s=1.5+s;的形式,仍然必须要有重载运算符RMB operator +(double,RMB&)来支持,因为在表达式1.5+s中,左面的1.5不能匹配RMB:operator+(RMB&)中的隐含类对象,由于没有双目运算符的非成员形式,所以也无法利用类的转换来创造匹配的条件。这就是为什么有些运算符重载(如复数类的+、运算)用非成员形式的原因。,59,本章主要内容,运算符重载的需要性 重载运算符作友元函数 运算符作成员函数 增量运算符重载 转换运算符重载 赋值运算符重载,前增量与后增量的区别 - 使用前增量时,对对象(操作数)进行增量修改,然后再返回该对象。所以前增量运算符 操作时,参数与返回的是同一个对象:这与基本数据类型的前增量操作类似,返回的也是左 值。 - 使用后增量时,必须在增量之前返回原有的对象值。为此,需要创建一个临时对象,存 放原有的对象,以便对操作数(对象)进行增量修改时,保存最初的值。后增量操作返回的是 原有对象值,不是原有对象,原有对象已经被增量修改,所以,返回的应该是存放原有对象值的临时对象。,C+约定,在增量运算符定义中,放上一个整数形参,就是后增量运算符 class Increase public: Increase(int x) : value(x) Increase,Increase /返回原有对象值 ,void main() Increase n(20); n.display(); (n+).display(); /显示临时对象值 n.display(); /显示原有对象 (+n).display(); +(+n); n.display(); (n+)+; /第二次增量操作对临时对象进行 n.display(); ,64,运行结果为 the value is 20 the value iS 20 the value iS 21 the value is 22 the value is 24 the value is 25 前后增量操作的意义,决定了其不同的返回方式。前增量运算符返回引用,后增量运算符返回值。 后增量运算符中的参数int只是为了区别前增量与后增量,除此之外没有任何作用。因 为定义中,无须使用该参数,所以形参名在定义头中省略。 对于(n+)+中的第二个+是对返回的临时对象所作的,从最后一行输出可以看出 对n的修改只发生一次。,65,非成员形式重载,前增量和后增量的非成员运算符,也有类似的编译区分方法。例如,下面的程序将 前增量和后增量运算符修改为非成员形式:,66,class Increase public: Increase(int x):value(x) friend Increase ,67,Increase /返回原有对象值 ,68,void main() Increase n(20); n.display(); (n+).display(); /显示临时对象值 n.display(); /显示原有对象 +n; n.display(); +(+n); n.display(); (n+)+; /第二次增量操作对临时对象进行 n.display(); cin.get(); ,69,运行结果为: the value iS 20 the value iS 20 the value iS 21 the value is 22 the value iS 24 the value iS 25 可见,前增量和后增量运算符的定义以及成员形式与非成员形式稍有不同,但前增量和后增量运算符的使用完全相同。,70,本章主要内容,运算符重载的需要性 重载运算符作友元函数 运算符作成员函数 增量运算符重载 转换运算符重载 赋值运算符重载,程序中在进行赋值、计算、给函数传值以及从函数返回值时,经常会发生类型之间的转换。 怎样转换用户自定义类型呢? 通过转换构造函数能把其他类型(包括内部类型)的对象转换为某个特定类型的对象。 转换运算符可以把一种类的对象转换为其它类的对象或内部类型的值。,转换运算符只能是一个非静态的成员函数,而不能是友元函数。 在类定义体中声明形式: operator 类型名(); 它没有返回类型,因为类型名就代表了它的返回类型,故返回类型显得多余。 转换运算符将对象转换成类型名规定的类型。转换时的形式就像强制转换一样 如果 没有转换运算符定义,直接用强制转换是不行的,因为强制转换只能对基本数据类型进行操 作,对类类型的操作是没有定义的。,73,定义函数体: 类名:operate type() / return type类型的对象 ,下面的程序在类中定义了转换运算符,在主函数中将double数分别显式和隐式转换成RMB对象: class RMB public: RMB(double value=0.0); operator double() return yuan+jf/100.0; void display() cout(yuan+jf/100.0)endl; protected: unsigned int yuan; / 元 unsigned int jf; / 角分 ;,RMB:RMB(double value) yuan=value; jf=(value-yuan)*100+0.5; void main() RMB d1(2.0),d2(1.5),d3,d4; d3=RMB(double)d1+(double)d2); /显式转换 d3.display(); /隐式转换 d4=d1+d2; d4.display(); ,76,运行结果为: 3.5 对于d3=d1+d2,C+系统依次: (1)寻找成员函数的+运算符(此处未找到); (2)寻找非成员+运算符(此处未找到); (3)由于存在内部运算符operator +(double,double);所以假定匹配其程序中的加法; (4)寻找能将实参(RMB对象)转换成double型的转换运算符operator double()(找到 ) 于是,d1,d2转换成double型,匹配内部的double加法,得到一个double的结果值,然后,对左面是RMB对象的赋值运算符,将右面的表达式转换成RMB临时对象,赋值给RMB对象d3。,77,转换运算符的优点: 有了转换运算符,不必提供对象参数的重载运算符。可以从转换路径,到达double型,进行基本运算,得到double结果,再构造回来。 转换运算符的缺点: 无法定义其类对象运算符操作的真正含义,因为转换之后,只能进行其它类型的运算符操作(如double加法运算); 通过提供一个double转换,所有甚至无意义的RMB运算也将获得double转换而得以可操作。,78,转换运算符与转换构造函数(简称转换函数)互逆。例如,RMB(double)转换构造函数将double转换为RMB,而RMB:operator double()将RMB转换成double。 除此之外,还要防止同一类型提供多个转换路径(转换的二义性),它会导致编译出错,79,下面的代码将使编译出错: class A public: A(B&b); /用B类对象构造A对象(B类对象转换成A类对象) /. ; class B public: operator A(); /将B类对象转换成A类对象 /. ; void main() B sb; Aa=A(sb); /A(sb)是构造还是转换? 遇到A(sb)时,编译找到A的转换函数,准备将其转换成A对象,可是又从B类找到转换运算符,也可转换成A对象,由于多义性,编译报错。,归纳: 系统对于语句d3=d1+d2的处理步骤: 寻找成员函数的重载加法运算符 寻找友元函数的重载加法运算符 假定匹配内部运算的加法运算 寻找能将RMB对象转换成double型的转换运算符。 有了转换运算符,可以不必提供用户自定义类型的基本运算符(如+、-)重载吗?,转换运算符 和 转换构造函数的一个很好的特点是:当需要的时候,编译器可以为建立一个临时对象而自动的调用这些函数。 要防止同一类型提供多个转换路径,而导致转换的二义性。,class A public: A(B ,/ error,83,本章主要内容,运算符重载的需要性 重载运算符作友元函数 运算符作成员函数 增量运算符重载 转换运算符重载 赋值运算符重载,84,为什么要赋值运算符,只要是用户定义的类或结构,都应能进行赋值运算,这也是继承了C语言: struct Sint a,b; S a,b; a=b; /c语言允许如此赋值 -数组名不能赋值,一个数组名代表一个数据类型的集合,实质上是一个常量指针,所 以它不能: int a5; int b=3,4,5,6,7; a=b; /error,85,对任何类,像拷贝构造函数一样,C+也默认提供赋值运算符,但要区别拷贝构造函数 和赋值运算符: void fn(MyClass& mc) MyClass newMC=mc; /这是拷贝构造函数 newMC=mc; 这是赋值运算符 当拷贝构造函数执行时,newMC对象还不存在,拷贝构造函数起初始化的作用。当赋值 运算符在newMC上执行时,它已经是一个MyClass对象。 在拷贝构造函数中,我们碰到浅拷贝和深拷贝的问题,赋值运算符也同样, 什么时候浅拷贝不合适,就应提供成员赋值运算符,86,如何重载赋值运算符,重载赋值运算符与重载其它运算符类似。 下面的程序提供了赋值运算符作为Name类的公共成员,以使主函数(普通函数)中两个对象之间允许互相赋值:,87,#include #include class Name public: Name() pName = 0; Name(char* pn) copyName(pn); Nam

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论