程序设计-第5章继承与派生_第1页
程序设计-第5章继承与派生_第2页
程序设计-第5章继承与派生_第3页
程序设计-第5章继承与派生_第4页
程序设计-第5章继承与派生_第5页
已阅读5页,还剩77页未读 继续免费阅读

下载本文档

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

文档简介

1第二部分面向对象的程序设计

第3章类和对象(一)第4章类和对象(二)第5章继承和派生第6章虚函数与多态性第7章运算符重载第8章模板第9章标准模板库STL第10章C++语言的输入和输出2第5章继承和派生本章重点:继承与派生的概念;派生类的构造函数和析构函数的执行顺序与规则;多继承的声明与实现;基类成员访问原则;赋值兼容性;虚基类的概念;35.1继承与派生的概念

继承是面向对象程序设计中重要的特性。继承主要是指在己有类的或称为基类的基础上创建新类的过程,这个新类就是派生类。派生类自动的包含了基类的成员,包括所有的数据和操作,而且它还可以增加自身新的成员4在C++中,一个派生类可以从一个基类派生,也可以从多个基类派生,从一个基类派生的称为单继承,如图5.1。图5.2中的树型结构图可以体现学生体系的概念。图5.1单继承

图5.2类的层次树型结构图5一个派生类从两个或多个基类派生则称为多继承,如图5.3所示,它使一个类可以融合了多个类的特征,例如在现实生活中的在职研究生的概念,他是在职人员,又是研究生,如图5.4所示,从图中还可以看到一个有趣的现象,在职人员类本身是单继承的基类,教师和职员都是它的具体子类,而其又是在职研究生的多重基类,提供在职人员的基本特征。图5.3多继承

图5.4单继承与多继承

6继承机制除了支持软件复用外,还具备以下三个作用:对事物进行分类。支持软件的增量开发。对概念进行组合。

7前面的知识中,我们学习了如何定义类和如何实现类的抽象与封装,通常在不同的类中,数据成员和函数成员都是不同的,但对于某些特定的问题,有时候两个类的基本或大部分内容是相同的,在图5.2中给出了学生体系的概念,我们利用现有知识可以首先声明了一类来描述学生这一基本概念,如下:classStudent{private: intnumber; charname[20];public:Student(){ number=0;name[0]=’\0’;}VoidSetValue(intn,char*s1){ number=n; Strcpy(name,s1);} voidPrint() { cout<<”Number:”<<number<<endl; cout<<”Name:”<<name<<endl; }};8如果现在需要一个新类UGStudent来描述大学生概念,除上述的基本成员外,还需要用到年龄、年级等信息,我们可以如下定义此类:classUGStudent{private: intnumber; charname[20]; intage; intgrade;public: voidPrint() { cout<<”Number:”<<number<<endl; cout<<”Name:”<<name<<endl;cout<<”Age:”<<age<<endl;cout<<”Grade:”<<grade<<endl;

}};95.2派生类的声明

在C++中类的继承关系可以用如下语法表示:class派生类名:继承方式

基类名{

派生类成员声明};需要注意的是,基类的构造函数和析构函数不能被派生类继承,派生类若要初始化基类的数据成员必须在构造函数中初始化。10【例5.1】用继承重新定义UGStudent类。

/*05_01.cpp*/classUGStudent:publicStudent{private: intage; intgrade;public: UGStudent(){ SetValue(0,””); age=0;grade=0;}

UGStudent(intn,char*s1,inta,intg){ SetValue(n,s1); age=a;grade=g;} voidPrintExtra() { cout<<”Age:”<<age<<endl;cout<<”Grade:”<<grade<<endl;

}};11用主函数进行测试:intmain(){ UGStudentst1(100,”wang”,18,1); st1.Print(); //调用基类的函数

st1.PrintExtra(); //调用派生类新定义的函数

return0;} 12Number:100Name:wangAge:18Grade:1程序的运行结果为:13图5.5基类与派生类中的成员

145.3派生类的访问属性

类的成员可以分为public(公有)、protected(保护)和private(私有)三种访问权限。类的非静态成员函数可以访问类中的所有成员,但是通过类的“对象.成员”方式(在类的作用域之外),则只能访问该类的公有成员。类的继承方式有公有继承(public)、保护继承(protected)和私有继承(private)三种。不同的继承方式,导致原有基类成员在派生类中的访问属性也有所不同。

15表5.1不同继承方式下的访问控制权限基类成员的权限继承方式publicprotectedprivatepublic在派生类中为public在派生类中为protected在派生类中为private派生类的成员函数和类的作用域之外,都可以直接访问派生类的成员函数可以直接访问派生类的成员函数可以直接访问protected在派生类中为protected在派生类中为protected在派生类中为private派生类的成员函数可以直接访问派生类的成员函数可以直接访问派生类的成员函数可以直接访问private在派生类中被隐藏,无法访问在派生类中被隐藏,无法访问在派生类中被隐藏,无法访问任何方式都不能直接访问,但可以通过基类的public、protected成员函数间接访问任何方式都不能直接访问,但可以通过基类的public、protected成员函数间接访问访问任何方式都不能直接访问,但可以通过基类的public、protected成员函数间接访问访问16对于静态成员来说,与普通成员函数组合,将产生以下两种情况:(1)派生类中静态函数对基类中静态成员的访问。(2)派生类的普通成员函数要访问基类中的静态成员。静态成员的访问控制变化完全遵循表5.1的规则,这两种情况和派生类中普通成员函数访问基类中普通成员没有区别。

17【例5.2】公有继承时的访问控制权限。

/*05_02.cpp*/#include<iostream>usingnamespacestd;classBase{private: inta;voidfun1(){cout<<a<<endl;}protected:intb;voidfun2(){cout<<c<<endl;}public:intc;voidfun3(){cout<<b<<endl;}voidseta(inti) //修改私有成员a的值{a=i;}int geta() //返回私有成员a的值{returna;}Base(inti,intj,intk) //基类的构造函数{a=i;b=j;c=k;}};18classSub:publicBase{private: intd;public:Sub(inti,intj,intk,intm):Base(i,j,k)//派生类构造函数{d=m;}voidtest(){//cout<<a<<endl; //错误,无法访问基类的私有成员cout<<b<<endl; //正确,可以访问基类的保护成员cout<<c<<endl; //正确,可以访问基类的公有成员//fun1(); //错误,无法访问基类的私有成员fun2(); //正确,可以访问基类的保护成员fun3(); //正确,可以访问基类的公有成员seta(10); //正确,间接访问基类成员acout<<d<<endl; //正确,可以访问派生类的私有成员}};19intmain(){Baseb1(5,6,7);//cout<<b1.a; //错误,无法访问对象的私有成员//cout<<b1.b; //错误,无法访问对象的保护成员cout<<b1.c<<endl; //正确,可以访问对象的公有成员cout<<b1.geta()<<endl; //正确,间接访问对象的私有成员aSubs1(11,15,19,22);s1.test(); //正确,可以访问对象的公有成员s1.c=200; //正确,可以访问对象的公有成员s1.fun3(); //正确,可以访问对象的公有成员return0;}205.4派生类的构造函数和析构函数

在继承机制中,基类的构造函数和析构函数是不能继承的。派生类的构造函数负责对来自基类数据成员和新增加的数据成员进行初始化。所以在执行派生类的构造函数时,需要调用基类的构造函数。215.4.1派生类构造函数和析构函数的执行顺序

通过继承,派生类得到了基类的成员,因此派生类对象中既包括自身类的数据成员还包括通过继承从基类中得到的数据成员。在派生类中还可用其他类来定义对象作为成员,又涉及到派生类中对象成员的构造问题,则当用派生类定义对象后,派生类对象、对象成员、基类对象的构造函数的调用顺序如下:基类的构造函数。对象成员的构造函数(如果有的话),有多个时按声明的顺序。派生类的构造函数。22【例5.3】派生类构造实例。

/*05_03.cpp*/#include<iostream>usingnamespacestd;classB{public: B(){cout<<”ConstructB”<<endl

;}};classC{public:

C(){cout<<”ConstructC”<<endl

;}};classD:publicB{private: Cc1;public: D(){cout<<”ConstructD”<<endl

;}};intmain(){ Dd1;return0;}23constructBConstructCConstructD程序的运行结果为:24析构函数与构造函数执行的顺相反,将按如下顺序执行:(1)派生类的构造函数;(2)对象成员的构造函数(如果有的话),有多个时与声明的顺序相反;(3)基类对象的析构函数。25对例5.3中的程序进行改造,为每一个类添加析构函数,然后再进行测试。

classB { public: B(){cout<<”ConstructB”<<endl;} ~B(){cout<<”DeconstructB”<<endl;} }; classC { public: C(){cout<<”ConstructC”<<endl;} ~C(){cout<<”DeconstructC”<<endl;} }; classD:publicB { private: Cc1; public: D(){cout<<”ConstructD”<<endl;} ~D(){cout<<”DeconstructD”<<endl;} }; intmain() { Dd1; return0; }26ConstructBConstructCConstructDDestructDDestructCDestructB程序的运行结果为:275.4.2派生类构造函数和析构函数的构造规则

在C++中,类的机制非常清楚、严格地划分了各自的权限和责任。是哪个类的操作,必须由那个类调用;是谁的对象,就必须由该类的构造函数来完成对其构造的工作。因此,对派生类中基类成员的构造,必须由基类构造函数完成,而不能由派生类的构造函数越权去构造。派生类构造函数主要负责调用基类构造函数并提供基类构造函数所需的参数。28下面分两种情况讨论派生类对象的构造:

1.如基类中定义了默认构造函数,且该默认构造函数能够完成派生类对象中基类成员的构造,则派生类构造函数无需显式调用基类构造函数,直接调用基类的默认构造函数即可,这是一种较为简单的情况,例5.3中的继承就属于此类情况,下面的例子也可以说明这一点。29【例5.4】分析下面程序的输出结果。

/*05_04.cpp*/#include<iostream> usingnamespacestd; classBase { public: Base(){a=0;} Base(inti){a=i;} protected: inta; }; classDerived:publicBase { public: Derived(){b=0;} Derived(inti){b=i;} voidPrint() { cout<<"a="<<a<<",b="<<b<<endl; } private: intb; };

30intmain() { Derivedd1; Derivedd2(12); d1.Print(); d2.Print(); return0;}31a=0,b=0a=0,b=12程序的运行结果为:322.若基类中定义了有参数的构造函数,或者所定义的默认构造函数不能完成基类成员的构造,则必须通过派生类构造函数显式向调用基类的构造函数,向带参数的构造函数传递参数,这需要用到“成员初始化列表”的语法。另外,对于派生类中普通数据成员的初始化,以及对象成员的构造也可以放在成员初始化列表中完成。此时这些以逗号隔开的基类构造函数调用数据成员初始化和构造的放置顺序可以是任意的。因此派生类的构造函数定义一般格式如下:派生类名(参数列表):基类构造函数(参数列表1),子对象成员1(参数列表)……{

派生类构造函数体}33【例5.5】派生类构造函数举例。

/*05_05.cpp*/#include<iostream> #include<cstring> usingnamespacestd; classDate //日期类 {

private: intyear,mon,day; //年、月、日成员变量

public: Date(inty=2009,intm=6,intd=10)//构造函数 {

year=y;mon=m;day=d; } voidPrint() //输出数据,格式为:年-月-日 {

cout<<year<<"-"<<mon<<"-"<<day<<endl; } };34classStudent //定义学生基类 {

protected: intnumber; //数据成员

charname[20]; charsex; public: Student() //重定义的默认构造函数 {

number=0; strcpy(name,"Noname"); //默认名字

sex='M'; //默认性别,男性(male)d } Student(intn,char*s,charx)//带参数的构造函数 {

number=n; strcpy(name,s); sex=x; } };35//大学生派生类

classUGStudent:publicStudent { public: UGStudent(intn,char*s,charx,inta,inty,intm,intd): Student(n,s,x),birth(y,m,d) { age=a; } UGStudent() //此处省略了Student()调用 {

age=0; } voidPrint()//输出信息 {

cout<<"number:"<<number<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; cout<<"age:"<<age<<endl; cout<<"birthday:"; birth.Print(); } private: intage; Datebirth; //对象成员 };36//主函数

intmain() { UGStudentst1; //用派生的默认构造函数定义对象

UGStudentst2(1001,"Zhang",'F',20,2009,6,11);//带参数构造

st1.Print(); st2.Print(); return0; }37number:0name:Nonamesex:Mage:0birthday:2009-6-10number:1001name:Zhangsex:Fage:20birthday:2009-6-11程序的运行结果为:385.5多继承

5.5.1多继承的声明

多继承下派生类的声明格式如下:class派生类名:继承方式1基类名,继承方式2基类名2……

{派生类类体;};其中,继承方式1、继承方式2…是三种继承方式:public、private和protected之一。

39如下为最基本的定义形式:

classB1 {

… }; classB2 {

… }; classD:publicB1,publicB2 {

…};40图5.6多继承类D中的成员

415.5.2多继承的构造函数与析构函数

在多继承的情况下,派生类的构造函数格式如下:派生类名(参数列表):基类名1(参数表1),基类名2(参数表2)……,子对象名(参数表n)……{派生类构造函数体;}42多继承下派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。派生类构造函数执行顺序是先执行所有基类的构造函数,再执行派生类本身构造函数。处于同一层次的各基类构造函数的执行顺序取决于声明派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。另外,析构函数的调用顺序则与构造函数完全相反。43【例5.6】多继承举例。

/*05_06.cpp*/#include<iostream> #include<cstring> usingnamespacestd;//定义研究生基类

classGStudent { protected: intnumber; //学号

charname[20]; //名字

charsex; //性别,男性:M,女性:F public: GStudent(intn,char*s,charx)//带参数的构造函数 {

number=n; strcpy(name,s); sex=x; cout<<"ConstructGStudent."<<endl; } ~GStudent() //析构函数 {cout<<"DestructGStudent."<<endl;} };44classEmployee //职员类 {

protected: charename[20]; //职员名字

charjobname[20]; //工作名

public: Employee(char*sn,char*sj) //构造函数 {

strcpy(ename,sn); strcpy(jobname,sj); cout<<"ConstructEmployee."<<endl; } ~Employee() //析构函数 {cout<<"DestructEmployee."<<endl;} };45//在职研究生类,从两个基类派生

classGStudentHasJob:publicGStudent,publicEmployee { public: GStudentHasJob(intn,char*s,charx,char*sj): GStudent(n,s,x),Employee(s,sj) {cout<<"ConstructGStudentHasJob."<<endl; } ~GStudentHasJob() {cout<<"DestructGStudentHasJob."<<endl;} voidPrint()//输出信息 {

cout<<"number:"<<number<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; cout<<"job:"<<jobname<<endl; } };46//主函数

intmain() { //定义一个在职研究生对象,并对其初始化 GStudentHasJobst(1001,"zhang",'F',"teacher"); st.Print(); return0; }47Construct GStudent.ConstructEmployee.ConstructGStudentHasJob.number:1001name:zhangsex:Fjob:teacherDestructGStudentHasJob.DestructEmployee.DestructGStudent.程序的运行结果为:485.6基类成员访问和赋值兼容性

5.6.1基类成员名的限定访问和名字覆盖

若多个基类中定义有同名成员,则派生类对这些同名成员的访问可能存在冲突。为避免可能出现的成员访间冲突,需要用成员名限定的方法显式地指定要访问的成员。49【例5.7】成员访问冲突。

/*05_07.cpp*/#include<iostream> usingnamespacestd; classMP3Player //mp3播放器类 {

public: voidPlay() //播放音乐操作 {cout<<"Playmp3music."<<endl;} }; classVideoPlayer //视频播放器类 {

public: voidPlay() //播放视频操作 {cout<<"Playvideo."<<endl;} }; //新型的mp4播放器类

classMP4Player:publicMP3Player,publicVideoPlayer { public: /*…………*/ };50intmain() { MP4Playermp4; //mp4.Play(); //去掉注释,本行将产生Play()函数访问不明确的错误 mp4.MP3Player::Play(); mp4.VideoPlayer::Play(); return0; }51Playmp3music.Playvideo.程序的运行结果为:52对于多继承,如果在不同的基类中定义了同名的成员,在派生类中要区分成员的来源,就必须使用成员名限定方法,即在成员名前加上各自基类的访问域限制即可。

53【例5.8】多继承中成员限定法。

/*05_08.cpp*/#include<iostream> usingnamespacestd; classB1 //基类B1 { public: intm; //成员变量m B1() //构造函数 {m=0;} }; classB2 //基类B2 { public: intm; //成员变量m B2() //构造函数 {m=100;} };54classD:publicB1,publicB2 //派生类

D { public: voidTest() { //cout<<m<<endl; //此语句将引起二义性错误

cout<<"B1::m="<<B1::m<<endl;//输出基类B1中的成员m的值

cout<<"B2::m="<<B2::m<<endl;//输出基类B2中的成员m的值 } };

intmain() //主函数 {

Dd1; //派生类对象

d1.Test(); return0;}55B1::m=0B2::m=100程序的运行结果为:565.6.2名字覆盖

当派生类中定义有与基类中同名的成员时,则从基类中继承得到的成员被派生类的同名成员覆盖,派生类对基类成员的直接访问将被派生类中该成员取代,为访问基类成员,必须采用成员名限定方法。57【例5.9】成员访问冲突。

/*05_09.cpp*/#include<iostream> usingnamespacestd; classCircle //定义圆类 {

protected: floatradius; //半径

public: Circle(floatr) //构造函数 { radius=r; } floatArea() //求圆面积 {return3.14f*radius*radius;} };58classCylinder:publicCircle //圆柱体派生类 {

private: floatheight; //高度

public: Cylinder(floatr,floath):Circle(r) //构造函数 { height=h; } floatArea() //求圆柱体面积,覆盖了基类的Area()函数 { floatbotarea=0,sidearea=0; botarea=Circle::Area()*2; //底面积*2

sidearea=2*3.14f*radius*height;//侧面积

returnbotarea+sidearea; } floatVolume() //圆柱体积 { returnCircle::Area()*height;}//基类求面积乘高度 };59intmain() { Cylindercr1(10,5); //定义圆柱体对象

cout<<"BottomArea="<<cr1.Circle::Area()<<endl;//访问基类成员

cout<<"Area="<<cr1.Area()<<endl; //访问派生类成员

cout<<"Volume="<<cr1.Volume()<<endl; return0; }60BottomArea=314Area=942Volume=1570程序的运行结果为:61从上述程序可以看出,用派生类对象访问与基类中同名的成员时,会调用本类中的成员,而不会访问到基类成员。为访问到基类的同名成员,需要以成员名限定的方法来指明,如在Cylinder类中的求面积和体积函数就用到了基类的Circle::Area()函数。另外,要注意的一点是,在派生类如果定义了和基类中同名的函数,则基类中所有的同名的重载函数都将被覆盖,即在派生类中或通过派生类对象都无法直接访问基类的任何一个同名函数,如图5.7中定义了一个基类和派生类,62图5.7派生类对基类的名字覆盖

635.6.3赋值兼容规则

在派生类对象和基类对象之间赋值时需要注意赋值的方向,即这些赋值操作需要满足赋值兼容规则。赋值兼容规则包括:(1)基类对象可以赋值给基类对象,也可以把派生类对象赋值给基类对象。(2)基类指针可以指向基类对象,也可以指向派生类对象。(3)基类引用可以指向基类对象,也可以指向派生类对象。64例如,有基类Base和其派生类Derived,可以定义相应的对象、指针:Baseb1;Base*pb;Derivedd1;根据赋值兼容规则,在基类Base对象可以出现的任何地方都可以用派生类Derived对象来替代。(1)派生类对象可以赋值给基类对象,即派生类对象中来自基类成员,逐个赋值给基类对象的成员: b1=d1;(2)派生类的对象也可以初始化基类对象的引用: Base&rb=d1;(3)基类的指针赋值为派生类对象的地址: pb=&d1;65【例5.10】赋值兼容实例。

/*05_10.cpp*/#include<iostream> usingnamespacestd; classBase //基类Base { protected: intmember; public: Base() {member=0;} voidShow() //共有成员函数 {cout<<"Base::Show():"<<member<<endl;} }; classDerived1:publicBase //第1个派生类Derived1 { public: Derived1(inta) {member=a;} voidShow() //重写共有成员函数Show {cout<<"Derived1::Show():"<<member<<endl;} };66classDerived2:publicDerived1//第2个派生类Derived2 { public: Derived2(inta):Derived1(a) {} voidShow() //重写共有成员函数Show {cout<<"Derived2::Show():"<<member<<endl;} }; voidTest(Base*pb) //测试函数,用基类指针作参数 {pb->Show();} voidTest(Base&br) //测试函数,用基类引用作参数 {br.Show();} intmain() //主函数 {

Baseb0; //基类Base对象

Derived1d1(5); //派生类Derived1的对象

Derived2d2(10); //派生类Derived2的对象

Base*pb0; //基类指针pb0 pb0=&b0; //基类指针pb0指向基类对象b0 Test(pb0); b0=d1; //基类对象赋值为子类对象

Test(pb0); //测试输出

pb0=&d1; //基类指针pb0指向基第一派生类Derived1的对象d1 Test(pb0); Test(d2); //第2派生类Derived2的对象d2的引用作参数传给Test函数

return0; }67Base::Show():0Base::Show():5Base::Show():5Base::Show():10程序的运行结果为:685.6虚基类

5.6.1提出问题

在多继承关系中,如果某个派生类D的多个基类(如类Bl和B2)派生自另一个公共基类B0,则在派生类对象中,会通过不同的继承路径多次得到基类B0的成员,即同时存在多份基类B0的成员。通过派生类D的对象访问这些成员时,会出现对这些成员的访问冲突。为解决冲突问题可以使用成员名限定的方法来唯一标识某个成员所属的基类,但是这不能从根本上解决问题:派生类对象中存在基类成员的多个副本,如图5.8所示。69图5.8多继承关系及派生类的成员构成UML图

705.6.2虚基类的概念

为使得公共基类B0在派生类D0中只产生一份基类成员,则需要将这个共同基类B0设置为虚基类,让基类Bl和B2从基类B0虚拟继承,这时从不同的路径继承过来的同名数据成员在派生类中就只有一个副本。同一个函数名也只有一个映射。这样就解决了同名成员的唯一标识问题。使用虚基类,可以使公共基类的成员在其间接派生类中只保留一份。使用虚基类后,4个类之间的关系如图5.9a所示,这时派生类中的成员如图5.9b所示71图5.9虚基类多继承关系及派生类的成员构成UML图

72定义虚基类的格式如下:class派生类名:virtual继承方式

基类名称{

……};73在图5.9中的几个类可以写成如下形式:classB0{public: intnv0;};classB1:virtualpublicB0{public: intnv1;};classB2:virtualpublicB0{public: intnv2;};classD0:publicB1,publicB2{public: intnv3;};

745.6.3虚基类的初始化

关于虚基类的初始化,有如下两条规则:(1)所有从虚基类直接或者间接派生的类必须在该类构造函数的成员初始化列表列出对虚基类构造函数的调用,但是只有实际构造对象的类的构造函数才会引发对虚基类构造函数的调用,而其他基类在成员初始化列表中对虚基类构造函数的调用都会被忽略,从而保证了派生类对象中虚基类成员只会被初始化一次。(2)若某类构造函数的成员初始化列表中同时列出对虚基类构造函数和非虚基类构造函数的调用,则会优先执行虚基类的构造函数

75【例5.11】

设置虚基类以解决二义性

/*05-11.cpp*/ #include<iostream> usingnamespacestd; classBase //虚基类

温馨提示

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

评论

0/150

提交评论