面向对想程序设计5_第1页
面向对想程序设计5_第2页
面向对想程序设计5_第3页
面向对想程序设计5_第4页
面向对想程序设计5_第5页
已阅读5页,还剩155页未读 继续免费阅读

下载本文档

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

文档简介

1、第四章类和对象1第四章 类与对象类对象构造函数和析构函数const成员函数成员对象静态成员友元小结2第四章 类与对象类对象构造函数和析构函数const成员函数成员对象静态成员友元小结34.1 类类的定义class 类名 ;说明:1、类名代表所定义的类的名字,用标识符表示。 2、成员描述给出该类的对象所有的成员的说明,它包 括成员函数和数据成员。 3、在类定义的成员描述中还包含对成员的访问控制。4一个类中的方法可以直接访问同类中的任何成员。5在C+定义中,可以用访问控制修饰符public、private或protected来描述对类成员的访问限制。public:public成员的访问不受限制,在

2、程序中的任何地方都可以访问一个类的public成员。private:private成员只能在本类(本类的成员函数)和友元中访问。protected:protected成员只能在本类、派生类和友元中访问。成员的访问控制:信息隐藏6在类定义中可以有多个public、private和protected访问控制说明,它们出现的先后顺序无关。C+的默认访问控制是private。成员的访问控制良好编程习惯:为了保证程序的清晰性和可读性,每个成员访问说明符在类定义中只能使用一次。请将public成员放在最前面,这样更便于查找。7一般情况下,类的数据成员和在类内部使用的成员函数应该指定为private,只有提

3、供给外界使用的成员函数才指定为public。指定为public的成员构成了类与外界的一种接口。操作一个对象时,只能通过访问对象类中的public成员实现。成员的访问控制软件工程知识:根据经验,数据成员应该声明为private,成员函数应该声明为public,如果某些成员函数只是被该类的其他成员函数访问,那么它们更适合声明为private。8类的定义示例定义一个Student类class Studentprivate: /访问控制说明int number , score;public: /访问控制说明void init() number = 1001;score = 100; void show

4、()coutnumberendlscore= 0 & hh 数据成员名对象指针-成员函数名(实参列表)对象指针-成员名等价:(*对象指针).成员名29间接方式 间接创建和标识对象是指在程序运行时刻,通过new操作来创建对象。所创建的对象称为动态对象,其内存空间在程序的堆区中。动态对象用delete操作撤消(即使之消亡)。动态对象需要通过指针变量来标识。对象的创建和标识30对象的创建和标识单个动态对象的创建与撤消。A *p;p=new A; delete p;A *p;p=(A *)malloc(sizeof(A); free (p);31对象的创建和标识动态对象数组的创建与撤消A *p;p=n

5、ew A100; delete p;A *p;p=(A *)malloc(sizeof(A)*100); free(p);32类作用域类定义构成一个作用域:类作用域,其中的标识符局部于类定义,它们可以与类定义外的全局标识符或其他类定义中的标识符相同。他们包括:数据成员成员函数在类定义外使用类定义中的标识符时,需通过对象名受限或类名受限。在类定义中使用与局部标识符同名的全局标识符时,需要在全局标识符前面加上全局域分辨符(:)来实现。33class Studentprivate:int number,score;public:void init();void Student:init()numbe

6、r = 1001;score = 100;类作用域34类作用域void init(); class Studentprivate: int number; public: void init(int number); void f(); void Student:f() :init();/调用全局函数init 35class Studentprivate:int number;int score;public:void init(int number,int score)Student:number = number;Student:score = score;void main()Stude

7、nt s1; s1.init();36class A public: void f(); void g(int i) x=i; f(); private: int x,y,z;aba.xa.ya.zb.xb.yb.zA a,b;g(int i)37this指针每个成员函数都有一个隐藏的指针类型的形参this,其类型为: *const this;成员函数中对类成员的访问都是通过this指针进行的。void g(A *const this,int i)this-x=i; this-f();void g(int i)x=i; f(); a.g(3);A:g(&a,3);38class Student

8、private:int number;int score;public:void init(int number,int score)this-number = number;this-score = score;void main()Student s1; s1.init();39void func(A * p) class A int x; public: void f()func(?); void g(int i)x=i;f();A a,b;a.f();b.f();要求:调用a.f()时,在A:f中调用func(&a);调用b.f()时,在A:f中调用func(&b);40练习:应在下列

9、程序划线处填入的正确语句是( )。void init(); class Studentprivate: int number; public: void init(int number); void f();void Student:init(int number) _= number; void Student:f() _ /调用全局函数init 41练习A. this-number; ,:init(); B. this:number; ,:init();C. Student:number; ,init(); D. student-number; ,init();42小技巧:在以后的MFC编

10、程中,如果在成员函数中想调用同类中的某个成员,可以使用VC+提供的自动列出成员函数功能,使用this-,VC+将列出该类中的所有成员,我们可以从列表中选择我们想调用的成员。自动列出成员函数功能,可以提高编写速度,减少拼写错误。我们经常不能完全记住某个函数的完整拼写,但却能够从列表中辨别出该函数,自动列出成员函数的功能在这时就显得更加有用了。43事实上,在各种IDE编程环境中,我们通常都不可能记住也没有必要记住所有的函数,只要将常用的函数记住,其他不常用的函数只要记住其大概的写法和功能,在调用该函数时可以从自动列出成员函数中选取,这样可以大大节省我们的学习时间。我们不用花费大量的时间去死记硬背许

11、多函数,利用自动列出成员函数功能和帮助系统,就能够在编程时顺利地使用这些函数,等用的次数多了,也就在不知不觉中完全掌握了这些函数。 44第四章 类与对象类对象构造函数和析构函数const成员函数成员对象静态成员友元小结45构造函数什么是构造函数构造函数是一种特殊的成员函数,它是在对象诞生后第一个执行(并且是自动执行)的函数.46构造函数的特点构造函数的名称必须与类名相同构造函数没有返回值,可以有参数,可以重载构造函数一般是public的,但有时也把构造函数声明为私有的(private),其作用是限制创建该类对象的范围,这时只能在本类和友元类中创建该对象。程序中不能直接调用构造函数,在创建对象时

12、系统自动调用构造函数。47在创建一个对象时,对象类的构造函数会被自动调用来对该对象进行初始化。至于调用对象类的哪个构造函数,这可以在创建对象的时候指定。构造函数48class A public: A(); A(int i); A(char *p); A a1; 或 A a1=A(); A a2(1); 或A a2=A(1); 或A a2=1;A a3(“abcd”); 或A a3=A(“abcd”);或A a3=“abcd”;A a1();49class A public: A(); A(int i); A(char *p); A a4; A b5=A(),A(1),A(“abcd”),2,”

13、xyz”; A *p1=new A; A *p2=new A(2);A *p3=new A(“xyz”); A *p4=new A20; 50不带参数的(或所有参数都有默认值的)构造函数,即构造对象时不提供参数的构造函数称为默认构造函数。程序中不能同时出现无参数的构造函数和带有全部默认形参值的构造函数。构造函数51class A public: A(); A(int i=0); ;A a; 构造函数(ERROR)52C+规定,每个类必须有一个构造函数,没有构造函数,就不能创建任何对象。构造函数53构造函数C+又规定,如果一个类没有提供任何的构造函数,则C+提供一个默认的构造函数(由C+编译器提

14、供),这个默认的构造函数是一个不带参数的构造函数,该构造函数的函数体为空,不做任何的初始化工作。54只要一个类定义了一个构造函数,不管这个构造函数是否是带参数的构造函数,C+就不再提供默认的构造函数。因此,如果为一个类定义了一个带参数(且不是所有参数都有默认值)的构造函数,还想要创建一个对象而不提供参数,就需要自己定义一个默认构造函数。构造函数55class A public: A(int i); ;A a; 构造函数(ERROR)56构造函数示例把Student类中的函数init改成构造函数class Studentprivate:int number;int score;public:St

15、udent(int number,int score)Student:number = number;Student:score = score; ;void main()Student s1(1002,90);Student s2;构造函数也可以“类内声 明,类外定义”/错误,类中没有默认构造函数57构造函数错误预防技巧:除非没有必要初始化类的数据成员,否则请提供构造函数,这样可以保证当类的每个新对象被创建时,类的数据成员都用有意义的值进行了初始化。58析构函数什么是析构函数在对象行将毁灭但未毁灭之前一刻,最后执行(并且是自动执行)的函数。析构函数是“反向”的构造函数,析构函数不允许有返回值

16、,更重要的是析构函数不允许带参数,并且一个类中只能有一个析构函数.析构函数的作用正好与构造函数相反,对象超出其作用范围,对应的内存空间被系统收回或被程序用delete删除时,析构函数被调用.59注意:new和delete会调用构造函数和析构函数malloc和free不会调用构造函数和析构函数对于动态分配的数组对象,必须用delete ,而不能用delete代替delete 。delete gradesArray;首先调用每个对象的析构函数然后释放内存如果语句中没有包括 () 并且gradesArray 指向一个对象数组只有第一个对象的析构函数被调用60注意:常见编程错误:删除数组时,用dele

17、te代替delete 将导致运行时的逻辑错误。为保证数组中的每个对象都接受一个析构函数调用,数组生成的内存空间要用delete 运算符删除。类似地,总是使用delete运算符将分配给单个元素的内存空间删除。61析构函数的特点析构函数的名称与类名相同,前面加上“”析构函数没有返回值,没有参数,不能重载当对象被撤销时,系统自动调用析构函数类中未定义析构函数,系统会自动生成默认的函数体为空的析构函数析构函数62根据析构函数的特点,我们可以在构造函数中初始化对象的某些成员变量,给其分配内存空间(堆内存),在析构函数中释放对象运行期间所申请的资源.析构函数63析构函数示例在构造函数申请空间,析构函数释放

18、空间class Studentprivate:char *name;int number;int score;public:Student(char *name,int number,int score)this-name = new charstrlen(name) + 1;strcpy(this-name,name);this-number = number;this-score = score;Student()delete name;析构函数同样可以“类内 声明,类外定义”64析构函数示例namenumberscore栈内存堆内存zhangsanStu1对象Student stu1(“

19、zhangsan”,101,90);1019065注意无论构造函数被调用还是析构函数被调用,对象都是存在的。66class A int x; char *p;public: A(char *p,int x) this-p = new charstrlen(p) + 1; strcpy(this-p,p); this-x = x; A()delete p;void main()A a(“lisi”,23); aa.xa.p对象产生,系统在堆栈中分配内存空间栈内存67class A int x; char *p;public: A(char *p,int x) this-p = new chars

20、trlen(p) + 1; strcpy(this-p,p); this-x = x; A()delete p;void main()A a(“lisi”,23); aa.xa.p栈内存调用构造函数,完成初始化堆内存lisi23对象产生,系统在堆栈中分配内存空间68class A int x; char *p;public: A(char *p,int x) this-p = new charstrlen(p) + 1; strcpy(this-p,p); this-x = x; A()delete p;void main()A a(“lisi”,23); aa.xa.p栈内存调用构造函数,完

21、成初始化堆内存lisi23对象产生,系统在堆栈中分配内存空间对象生命周期结束,在结束前先调用析构函数69class A int x; char *p;public: A(char *p,int x) this-p = new charstrlen(p) + 1; strcpy(this-p,p); this-x = x; A()delete p;void main()A a(“lisi”,23); aa.xa.p栈内存调用构造函数,完成初始化23对象产生,系统在堆栈中分配内存空间对象生命周期结束,在结束前先调用析构函数对象生命周期结束,释放内存70析构函数在某些情况下,我们并不撤消对象,而只是

22、归还对象所申请的资源,这时我们可以通过显示地调用析构函数来实现。71小结对象的创建在c+中,有四种方法可以产生一个对象在栈中产生在堆中产生产生一个全局对象产生一个局部静态对象72小结对象的创建对于全局对象,程序一开始,其构造函数就先被执行。程序即将结束前其析构函数执行。(MFC application object)对于局部对象,当对象诞生时,其构造函数被函数执行。程序流程将离开该对象的存活范围(以致对象将毁灭)时,其析构函数执行。73小结对象的创建对于静态对象,当对象第一次被定义时其构造函数被执行。当程序将结束时(此对象因而遭致毁灭)其析构函数被执行,但比全局对象的析构函数早一步执行。对于以

23、new方式产生出来的局部对象,当对象诞生时其构造函数被执行。析构函数则在对象被delete时执行。74思考class Person;Person per1(30,“zhangsan”, 170);Person per2(per1);75拷贝构造函数什么是拷贝构造函数拷贝构造函数是一种特殊的构造函数,它的功能是用一个已知的对象来初始化一个被创建的同类对象。拷贝构造函数实际上也是构造函数,具有一般构造函数的所有特性,它是在初始化时被调用来将一个已知对象的数据成员的值逐值拷贝给正在创建的一个同类的对象。默认情况下系统自动创建拷贝构造函数76如果在类定义中没有给出拷贝构造函数,则编译系统将会隐式地为其

24、提供一个拷贝构造函数,该拷贝构造函数的行为是:逐个成员拷贝初始化。对于普通成员,它采用通常的初始化操作;对于成员对象,则调用成员对象类的拷贝构造函数来实现成员对象的初始化。拷贝构造函数77拷贝构造函数的定义类名(const 类名 &object) 拷贝构造函数78在Person类中添加拷贝构造函数拷贝构造函数class Personprivate: int height; int age; char name10;public: Person(const Person &person) height = person.height; age = person.age; strcpy(name,

25、); ;79class Personprivate:char *name;int age;int height;public:Person(int age,char *name,int height)this-name = new charstrlen(name) + 1;strcpy(this-name,name);this-age = age;this-height = height;Student()delete name;80思考Person p1(11,“zhangsan”, 150);Person p2(p1);81Person(const Person &a

26、) age=a.age; height=a.height; name=;系统提供的默认拷贝构造函数的行为82深拷贝和潜拷贝问题p1p2张三p2 = p1*nameheightage*nameheightage栈空间堆空间83深拷贝和潜拷贝问题类体内的成员需要动态开辟内存的时我们应自定义拷贝构造函进行深拷贝,以防止潜拷贝带来的堆内存的所属权产生混乱,从而造成析构错误84Person(const Person &a) age=a.age; height=a.height; name= new charstrlen()+1; strcpy(name,); 深拷贝和

27、潜拷贝问题85拷贝构造函数void f(Person s)Person a;f(a);86以下三种情况将调用拷贝构造函数定义对象时 A a1; A a2(a1);A a2=a1;A a2=A(a1);把对象作为值参数传给函数 void f(A x); A a; f(a); /调用时将创建形参对象x,并调用拷贝构造函数(用对象a)对其初始化。把对象作为返回值87A f() A a; return a;/创建一个A类临时对象,并调用拷贝构造函数(用对象a)对其初始化。 void main()A b; b=f();88const常量、引用的初始化问题?思考89class A int x; const

28、 int y=1; int &z=x; public: A() x=0; y=1; ;/error/error/ error,y是常量成员,其值不能改变90成员初始化表(在定义构造函数时)class A int x; const int y; int &z; public: A():z(x),y(1) x=0; ;91class A int x; const int y; int &z; public: A():z(x),y(1),x(0) ;92成员初始化表中成员初始化的书写次序并不决定它们的初始化次序,数据成员的初始化次序由它们在类定义中的说明次序来决定。当类中有常量数据成员或引用数据成员

29、时,如果类中定义了构造函数,则一定要在定义的所有构造函数的成员初始化表中对它们进行初始化,如果类中没有定义构造函数,则编译程序不会给该类生成一个默认构造函数。因此,这样的类程序是不能用于创建对象的。成员初始化表(在定义构造函数时)93程序运行的某个时刻,一个对象的所有数据成员的值反映了这个对象在该时刻的状态。在不同时刻,对象的状态可能是不一样的,对象状态的改变往往是由于对象处理了一条消息(某个成员函数被调用)。但是并不是每条消息都会导致对象状态的变化。有些消息只是获取对象在某时刻的状态。思考94第四章 类与对象类对象构造函数和析构函数const成员函数成员对象静态成员友元小结95在定义一个成员

30、函数时,可以给它加上一个const说明,表示它是一个获取对象状态的成员函数。例如: class A void f() const ;const成员函数96const成员函数函数声明和定义处都要加constclass A int x,y; public: void f() const ;;void A:f() const97const成员函数class A int x; public: int f() const ;class A int x; public: const int f() ;98在const成员函数体中不能修改数据成员的值,也不能调用该类中的非常成员函数。const成员函数软件工

31、程知识:如果成员函数不修改对象,最好将所有类成员函数声明为const。99class A int x; char *p; public: void f() const x=10;/error p=new char20;/error ;const成员函数100class A int x; char *p; public: void f() const strcpy(p,”abcd”); *p=A; ;const成员函数101const成员函数const对象软件工程知识:将对象声明为const有利于实现最低权限原则,这样试图修改对象就会产生编译时错误而非执行时错误。性能提示:把变量和对象声明为co

32、nst,这不仅是一种有效的软件工程原则,而且还能提高性能,因为如今复杂的优化编译器能对常量进行某些优化,但无法对变量进行优化。102const成员函数只有常成员函数才有资格操作常对象。class A int x,y; public: void f() const void g() ;const A a;a.f(); /OKa.g(); /error103const成员函数软件工程知识:可以对 const 成员函数进行非 const 版本的重载。编译器将根据调用函数的对象性质选择相应的重载函数来使用。如果对象是 const 的,则编译器使用 const 版本的重载函数;如果对象是非 const

33、的,则编译器使用非 const 版本的重载函数。104const关键字可以被用于参与对重载函数的区分。如: void print(); void print() const;const成员函数105在函数f中不能调用对象*pa或a的非const成员函数。void f(A *pa) ;void f(A &pa) ;const成员函数void f(const A *pa) ;void f(const A &pa) ;106思考107组合(Composition)是一种 has-a 关系一个类可以将其他类的对象作为成员一种强的“拥有”关系,体现了严格的整体和部分的关系,部分和整体生命周期一样。108

34、第四章 类与对象类对象构造函数和析构函数const成员函数成员对象类的组合静态成员友元小结1094.5 类成员是其它类的对象成员对象一个类的成员可以是另外一个类的对象。也就是说一个对象可以包含另一个对象(称为成员对象)。class Computer private: CPU c1,c2;class CPUprivate: double frequency;110成员对象class A int m; public: A() m=0; A(int m1) m=m1;class B int n; A a; public: B() n=0; B(int n1) n=n1;B b1,b2(1);111在

35、创建包含成员对象的对象时,对成员对象的初始化是由成员对象类的构造函数来实现的。默认情况下,成员对象由成员对象类的默认构造函数进行初始化。成员对象的初始化112成员对象的初始化class A int m; public: A() m=0; A(int m1) m=m1;class B int n; A a; public: B() n=0; B(int n1) n=n1;B b1,b2(1);113如需要调用成员对象的非默认构造函数对成员对象进行初始化,则要在包含成员对象的类的构造函数成员初始化表指出。成员对象的初始化114class A int m; public: A() m=0; A(in

36、t m1) m=m1;class B int n; A a; public: B() n=0; B(int n1):a(n1) n=n1;B b1,b2(1);115116117118119判断:是否正确?class A int m; public: A(int m1) m=m1;class B int n; A a; public: B() n=0; B(int n1) n=n1;B b1,b2(1);120构造函数的执行顺序是(如果有多个成员对象)按照成员对象在类的声明中出现的次序,依次调用其成员对象的构造函数。(注意:并不是按照初始化列表中给出的顺序)。再执行本类的构造函数的函数体。析构

37、函数的调用执行顺序与构造函数相反。成员对象的初始化121成员对象的初始化系统提供的隐式拷贝构造函数会去调用成员对象的拷贝构造函数。自定义的拷贝构造函数不会去调用成员对象的拷贝构造函数,必须要在成员初始化列表中显示地指出。若没有指出,则表示调用成员对象的默认构造函数。122class A;class B int z; A a;public: B(); B(const B& b):a(b.a) z=b.z;123成员初始化列表成员初始化列表一般成员常量成员引用成员自定义的拷贝构造函数调用成员对象的拷贝构造函数显示调用成员对象的构造函数124第四章 类与对象类对象构造函数和析构函数const成员函数

38、成员对象静态成员友元小结125同一个类的不同对象需要共享数据,怎么办?全局变量?4.6 静态成员class SavingAccountprivate: char m_name40;/存户姓名 char m_addr60;/存户地址 double m_total;/存款额 double m_rate;/利率 ;126静态数据成员必须在类外定义,定义时可以进行初始化 数据类型 类名:静态数据成员名=值; class A static int shared; int x,y; public: A()x=y=0; void increase_all() ; int A:shared=0; A a1,a

39、2;0shared0000a1a2a1.xa1.ya2.xa2.y127静态数据成员C+国际标准:const static int 或 enum 类型的数据成员可以在类定义中声明时初始化 class A static const int shared=0; int x,y; public: A()x=y=0; void increase_all() ; A a1,a2; 128静态数据成员具有默认构造函数的 static 成员对象因为它们的默认构造函数会被调用,所以不必初始化129静态数据成员具有静态生存期,不属于任何一个对象。类的静态成员与该类的对象存在与否没有关系.静态数据成员130静态数

40、据成员 class A int x,y; public: A()x=y=0; void increase_all() static int shared; ; int A:shared=0;int main() A a; a. shared=4; A: shared=4;131思考private的静态成员变量,不能在外部被访问.只能通过公有的成员函数访问.如果希望在产生任何对象之前就存取其class的private static成员变量.怎么办?132思考class A public: void getX(); private: static int x; ;int A:x=0;void A:

41、getX() coutx; coutx; int main() A a; a.getX();133静态成员函数class A public: static void getX(); private: static int x; ;int A:x=0;void A:getX() coutx; int main() A:getX();134静态成员函数静态成员函数没有隐藏的形式参数this.135静态成员函数 静态成员函数只能访问静态成员。静态成员函数136class A public: static void f(); private: int x; ;void A:f() coutx;/err

42、or 137class A public: static void f(A a); private: int x; ;void A:f(A a) coutx;/error couta.x;138静态成员的使用除了在类中访问静态成员外,还可以在类的外部访问public静态成员,这时有两种访问方式: 通过对象访问。 通过类名访问。 类的静态成员与该类的对象存在与否没有关系。139设计模式设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。设计模式就象经典的棋谱,不同的棋局,我们用不同的棋谱,免得自己再去思考和摸索。自从对象产生以来,在程序设计领域最具革命性的飞跃

43、是设计模式的引进。设计模式是对应于公认的编程问题的经典解决方案,它独立于语言之外,其表述方法的特殊性使他能应用于许多情况之下. 小知识140底层思维抽象思维向下,如何深入把握机器底层,从微观理解对象构造底层思维语言构造编译转换对象内存模型运行时机制向上,如何将我们周围的世界抽象为程序代码抽象思维面向对象组件封装设计模式架构模式141设计模式Singleton模式是做为全局变量的替代品出现的。所以它具有全局变量的特点:全局可见、贯穿应用程序的整个生命期,它也具有全局变量不具备的性质:同类型的对象实例只可能有一个。 小知识142第四章 类与对象类对象构造函数和析构函数const成员函数成员对象静态

44、成员友元小结143#include #include class Pointpublic:/外部接口Point(int xx=0, int yy=0) X=xx;Y=yy;int GetX() return X;int GetY() return Y; private:/私有数据成员int X,Y;144double Distance( Point& a, Point& b) double dx=a. GetX() -b. GetX() ; double dy=a. GetY() -b. GetY() ; return sqrt(dx*dx+dy*dy);int main() Point p1(3.0, 5.0), p2(4.0, 6.0); double d=Distance(p1, p2); coutThe distance is dendl; return

温馨提示

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

评论

0/150

提交评论