一章面向对象程序设计.ppt

上传人:本田雅阁 文档编号:2840549 上传时间:2019-05-26 格式:PPT 页数:102 大小:479.05KB
返回 下载 相关 举报
一章面向对象程序设计.ppt_第1页
第1页 / 共102页
一章面向对象程序设计.ppt_第2页
第2页 / 共102页
一章面向对象程序设计.ppt_第3页
第3页 / 共102页
一章面向对象程序设计.ppt_第4页
第4页 / 共102页
一章面向对象程序设计.ppt_第5页
第5页 / 共102页
点击查看更多>>
资源描述

《一章面向对象程序设计.ppt》由会员分享,可在线阅读,更多相关《一章面向对象程序设计.ppt(102页珍藏版)》请在三一文库上搜索。

1、第10章 面向对象程序设计,内容介绍,10.1 面向对象技术的基本概念 10.2 类的定义和对象 10.3 构造函数和析构函数 10.4 类的属性 10.5 this引用 10.6 类的静态数据成员和静态方法 10.7 类的继承性 10.8 类的多态性 10.9 抽象类和抽象方法 10.10委托 10.11事件 10.12索引指示器 10.13接口 10.14运算符重载 10.15命名空间,学习目标,掌握面向对象的程序设计思想; 掌握类的封装性、继承性和多态性的实现方法; 掌握接口、委托与事件的使用方法; 掌握运算符重载的方法。,10.1面向对象技术的基本概念,结构化程序设计的缺点:用此类语言

2、设计的程序结构清晰,使用方便,但是它将数据和对数据的处理过程分开,一旦数据结构改变,其相关处理过程必须修改,程序可重用性差,这给软件的调试和维护带来了困难。 20世纪九十年代,人们提出了面向对象的程序设计思想(OOP,Object Oriented Programming)。面向对象程序设计是C#编程的核心技术,使得程序的设计更加合理,而且易于维护。 OOP技术由5个最基本的概念组成:类(class)、对象(object)、方法(method)、消息(message)和继承(inheritance)。,1.类,是对一组具有相似特性的客观事物的抽象,是对事物的特性和功能的描述,这一点体现了类的封

3、装性。封装是一种程序设计机制,它绑定代码及其操作的数据,并使它们不受外界干涉和误用的影响,从而保证安全性。 类与传统的模块概念是不同的。模块的层次结构在逻辑上体现了模块间的功能概括关系,而类的层次结构在逻辑上体现的是类的继承关系,处于上层的类称为父类或基类,处于下层的类称为子类或派生类。,2.对象,对象是类类型的变量,是类的实例。 例如:35英寸康佳液晶彩电 ;42英寸康佳液晶彩电 一个类可以定义多个对象,对象的属性值可以不同,但它们的操作功能是相同的。,3.方法,方法是指实现对象所具有的操作功能的代码。每个对象一般包含若干种方法,每个方法有方法名和对应的一组代码。方法体现了对象的一种行为能力

4、,程序通过对象的方法,去获取或修改对象的属性。,4.消息,客观世界是有各种对象组成的,对象之间存在着联系,对象之间的联系是通过消息激活机制实现的。例如:张先生拿着电视遥控器在看电视,张先生是对象,电视机是对象,电视遥控器也是对象。当张先生按下遥控器的提高声音的按钮时,张先生就和遥控器之间建立了联系,即张先生向遥控器发出了要求提高声音的消息;遥控器对按钮进行判断(遥控器响应该消息),然后向电视机发出调高声音的信号,此时,遥控器和电视机之间也建立了联系,即遥控器向电视机发出了要求提高声音的消息;电视机接收到信号后经过判断(电视机响应该消息),提高了音量。 从这个例子中可以看出,消息由三部分组成:发

5、送对象、接受对象和消息的内容。在OOP系统中,向一个对象发送消息,就是调用那个对象的某个功能(函数),消息的实质是调用对象的成员函数。同一个对象可以接受不同形式的多个消息,产生不同的响应。同一个消息可以发送给不同的对象,得到的响应可能是不同的,这一点体现了类的多态性,多态性是OOP的主要特征之一。同时从该例中可以看出,消息也可以传递。,5.继承,继承指的是一个子类可以从现有的父类中派生出来,子类除了继承父类的特性和功能以外,还可以增加新的特性和功能。继承描述的是类间的一种层次关系,继承性是OOP的主要特征之一。继承的一个重要作用是实现代码重用,节省程序开发的时间。程序员可以利用现有的类,按照需

6、求修改该类,以得到一个满足要求的新类。例如程序员可以修改系统预定义的按钮控件,使它的外观呈现出椭圆形。程序员可以重新定义自定义类中从object类中继承来的Equals方法,实现自定义对象的相同判断。,10.2 类的定义和对象,1. 类的定义 类是一种用户自定义的数据类型。定义格式为: class 类名 访问权限修饰符 其他修饰符 类成员定义 ; 常用的访问权限有三种,分别为:private(私有)、public(公有)和protected(保护) 其他修饰符包括:static、readonly、const、virtual、override、sealed、abstract和new。 reado

7、nly表示只读修饰符,其后只能声明数据成员,readonly型数据成员只能在声明时或构造函数中初始化,其它地方不能修改其值。 const表示常量修饰符,其后只能声明数据成员,且只能在声明时初始化,其它地方不能修改其值。 如果成员声明前没有访问权限关键字,则默认为private访问权限。,10.2 类的定义和对象,2. 对象 对象是类的实例(instance),即类的变量。缺省定义格式为: 类名 对象名=new 类名(); 定义对象时,才会为对象的每一个实例数据成员在堆中依次分配存储空间。 通过对象,可以访问它的公有成员。,结构体与类的差异,结构体变量是值类型,而类变量(对象)是引用类型。值类型

8、在栈上分配空间,引用类型在堆上分配空间,所以,结构体变量相互赋值是相同数据存储在不同的栈空间中,引用类型相互赋值是两个对象引用同一个堆空间数据。 结构体只能从接口继承,不能从结构体继承;类则支持继承和派生。 结构体中不能初始化数据成员;类则可以初始化数据成员。 系统不给结构体提供默认构造函数,但用户可以显式定义造函数,结构体不提供析构函数;类则支持构造函数和析构函数。 结构体没有 abstract、sealed和protected 修饰符。 在表现抽象和多层次的类型时,建议采用类的方法;如果只是存储一些数据和少量逻辑时,建议使用结构实现。,【例10-1】定义带有身份证和姓名字段的人员类,并提供

9、接口函数计算年龄。 using System; namespace 教材_类和对象 class Program static void Main(string args) Person p1 = new Person(); p1.SetNameId(“王宏“,“320402196312091234“); p1.Display(); p1.name = “王力宏“; /p1.id = “320402197908231432“; 错误,不能通过对象访问其私有成员 p1.Display(); Console.ReadKey(); ,public class Person /声明字段 private

10、string id; /可以赋初值,相当于缺省值;不赋初值,则默认为NULL public string name; /可以赋初值,相当于缺省值;不赋初值,则默认为NULL public void Display() /可以在成员函数中访问所有数据成员 DateTime date1 = DateTime.Now; /获取计算机的当前时间 int nowy = date1.Year; string by = id.Substring(6, 4); int byi = int.Parse(by); int age = nowy - byi; Console.WriteLine(“身份证号:0,姓名

11、:1,年龄:2“, id, name,age); public void SetNameId(string pname,string pid) name = pname; id = pid; ,10.3 构造函数和析构函数,1.构造函数 构造函数是一种特殊的成员函数,它的函数名与类名相同,无返回类型。构造函数是在定义对象时自动调用的。构造函数与9.5节的普通函数一样,也可以进行重载,以实现对象的多种初始化方法。 2. 析构函数 对象和其他变量一样,都有生命周期;生命周期结束时,这些变量和对象就要被撤销。对象撤销时,系统自动调用其析构函数,并释放其占用的堆空间。析构函数的名字为类名,无参数,无返

12、回类型,也无任何修饰符。析构函数不能重载。,10.4 类的属性,如何修改对象的private字段呢?除了可以通过public接口函数,设置和读取private字段的方法外,C#还提供了“属性”的方法进行private字段的设置和读取。“属性”总是和某个或某些字段相关联。 “属性”本质上属于类的成员函数,提供set和get访问器,用于对其关联字段进行设置和读取,同时在set和get访问器中,可以根据程序逻辑,限制用户的设置和读取操作。 “属性”与字段的区别:定义对象时,系统为对象的实例字段分配存储空间,属性不会分配存储空间,属性本质上是方法。字段用小写字母定义,属性以大写字母定义。,属性定义格式

13、:,修饰符 数据类型名 属性名 set /设置关联字段的值 get /获取关联字段的值 数据类型名应与属性关联字段的类型名相同。 “属性”分为只读属性、只写属性和读/写属性。只读属性只带get访问器,只写属性只带set访问器,读/写属性带get访问器和set访问器。 例如:DateTime的Now属性是只读属性 注意:一个属性的get访问器和set访问器必须在属性的声明中一次性定义,不能分开定义。 为了简化代码,C#3.5提供了自动属性的概念,即类不需要显式提供关联字段,而是由编译器自动提供私有关联字段。 利用类的属性,可以减少修改字段的公有接口函数的定义。,10.5 this引用,系统为每一

14、个实例方法,提供了一个隐含的this参数,其引用调用该方法的对象,在方法内部,通过this,确定数据成员的归属问题。“this”是一个const型变量,只能使用,不能改变其值。当方法内的临时变量与数据成员同名时,需要在同名数据成员前显式加上this。,10.6 类的静态数据成员和静态方法,1.类的静态数据成员 “静态数据成员” :“static”修饰符 在定义对象时,要对其每一个实例成员分配存储空间。 同一个类的不同对象,其实例数据成员占用不同的存储空间,访问方法为“对象实例数据成员”。 类的静态数据成员是该类的所有对象共享的,其访问方法为“类静态数据成员”。 2. 类的静态方法 在定义类的方

15、法时,若在其声明前加“static”修饰符,则该方法为“静态方法”,不加“static”修饰符的方法为实例方法。静态方法只能访问该静态方法所在类的静态数据成员和静态方法。实例方法可以访问所有成员。如: System.Array的Sort、Reverse、Find等 3. 静态方法不含有this引用,所以通常要将实例对象作为参数传递到static方法中,实例方法中含有this引用,其所获取的实例成员值是该对象特有的。,【例10-5】用静态方法和静态数据成员实现对象个数的统计和显示。 using System; namespace 教材_静态成员函数 class Program static vo

16、id Main(string args) string output; Person p1 = new Person(); p1.Id = “320402198412302323“; p1.Name = “张飞“; p1.Sex = “男“; p1.Display(); Person p2 = new Person(“320403198712121234“, “王军霞“, “女“); p2.Display(); Person.ReportCount(); /只能通过类名访问静态成员 Console.ReadKey(); ,public class Person private string i

17、d; /不赋初值,则默认为NULL private string name ; /相当于类的全局变量,可以通过类名使用,每次增加一个对象,总人数加1 public static int totalcount; public string Id get return id; set if (value.Length != 18) return; id = value; public string Name get return name; set name = value; public string Sex set; get; public Person() /每次增加一个对象,人数加1 id

18、 = “未知“; name = “未知“; Sex = “未知“; totalcount+; ,public Person(string pid, string pname, string psex) /每次增加一个对象,人数加1 id = pid; name = pname; Sex = psex; totalcount+; Person() /每次结束一个对象,人数减1 totalcount-; Console.WriteLine(name + “使用完毕,“ + “还有“ + totalcount + “人在使用“); Console.ReadKey(); public static v

19、oid ReportCount() /在static函数内,只能使用静态成员; Console.WriteLine(“目前总人数为:0“, totalcount); public void Display() Console.WriteLine(“身份证号:0,姓名:1,性别:2.“, id, name, Sex); ,10.7 类的继承性,类的三大特性是封装性、继承性和多态性。 继承性指的是可以从一个或多个基类派生出一个新类,新类继承了基类的非私有成员,同时,新类又可以根据需要定义新的成员或重写从基类处继承的成员。 派生类定义格式为: Class 派生类名:基类名 派生类成员定义;,关于C#

20、中的继承,有以下几点说明: C#只支持单一继承,即只能直接从一个基类处继承。若需要有多个直接基类(多重继承),采用接口的方法实现。 继承是可传递的。如果从A派生出B,又从B派生出C,则C既继承了B的成员,又继承了A的成员。由于所有类的根基类是object类,所以,所有类都包含从object类继承来的Equals、GetType、 ToString公有方法。 基类的构造函数和析构函数都不能被继承,其它成员都可以被继承。在派生类中,可以直接使用基类的protected和public成员,但不能直接使用基类的private成员,可以通过基类的public成员函数访问基类private成员。 在声明派

21、生类构造函数时,必须正确调用基类构造函数,若不显式调用基类构造函数,则按基类的缺省构造函数调用。若基类不提供缺省构造函数,则编译错误。 在派生类中,可以采用new修饰符,重写基类的非virtual成员函数,以达到在派生类中屏蔽基类中非virtual成员函数的作用。 在派生类中,可以采用override修饰符,覆盖基类的virtual成员函数,以实现类的多态性。 派生类对象可以赋给基类对象。 成员查找路径:通过派生对象调用public成员时,首先在派生类中查找,若找不到,再到直接基类中查找,若还不存在,则继续沿着继承层次向更上一层的基类中查找,直到查找到为止。,【例10-6】用继承实现学生、工作

22、人员和一般人员的定义和使用。 using System; namespace 教材_继承 class Program static void Main(string args) Person p1=new Person(“320402197812121234“,“小刘“,“男“); p1.Display(); /调用基类的Display()方法 Console.WriteLine(); Student s1 = new Student(“320402199308311423“,“汪兰“,“女“,“大一“); s1.Display(); /调用派生类的Display()方法 s1.Name =

23、“马援“; /修改从基类中继承的公有属性值 s1.UpdateGrade(“大二“); /调用派生类新增的方法,修改其新增字段sclass s1.Display(); /调用派生类的Display()方法 worker w1 = new worker(“320402196305011423“,“蒋大为“,“女“,9800); w1.Display(); /调用派生类的Display()方法 w1.Wage = 9000; /修改派生类的新增属性Wage w1.Sex = “男“; w1.Display(); /调用派生类的Display()方法 Console.ReadKey(); ,publ

24、ic class Person private string id; public string name; public string Sex /定义自动属性,编译器自动提供关联私有字段 get; set; public string Name get return name; set name = value; public void Display() Console.Write(“身份证号:0,姓名:1,性别为:2“, id, name,Sex); public Person(string pid,string pname, string psex) name = pname; id

25、= pid; Sex=psex; ,class Student : Person string sgrade; /增加私有字段年级 public string Sgrade get return sgrade; set sgrade = value; public void UpdateGrade(string pgrade) sgrade = pgrade; public Student(string pid, string pname,string psex, string pgrade) : base(pid, pname, psex) /base为关键字,派生类的构造函数中必须提供基类

26、构造函数的调用,否则,按缺省方法调用 sgrade = pgrade; new public void Display() /new为修饰符,重写基类中的非虚相同方法 base.Display(); /调用基类中的方法 Console.WriteLine(“ 年级为:“+sgrade); ,class Worker : Person int wage; /增加私有字段工资 public int Wage get return wage; set wage = value; public void UpdateWage(int pwage) wage = pwage; public Worker

27、(string pid, string pname, string psex, int pwage) : base(pid, pname, psex) wage = pwage; new public void Display() base.Display(); Console.WriteLine(“ 工资为:“ + wage); ,10.8 类的多态性,多态性指同一消息作用于不同的对象时,能够有不同的响应。C#支持两种类型的多态性:静态多态和动态多态。 静态多态:通过方法重载来实现的,对象调用若干同名方法,系统在编译时,根据调用方法的参数个数、类型或顺序确定调用哪个同名方法,实现何种操作。

28、动态多态:通过虚函数实现的,程序运行时,根据基类对象所具体引用的派生对象,调用派生对象的覆盖虚函数,实现不同的操作。 静态多态与动态多态的区别:静态多态是在编译期间完成的,因此执行速度快;动态多态是在程序运行期间完成的,因此执行速度较慢,但它提高了程序的灵活性和抽象层次,使软件的可扩充性增强。,基类中虚函数定义格式为: public virtual 返回类型 虚函数名(参数列表) 函数体 派生类中覆盖虚函数定义格式为: public override 返回类型 虚函数名(参数列表) 函数体 必须注意: 派生类中的覆盖虚函数必须和基类中虚函数的函数名,返回类型,参数个数及类型完全一致。 stat

29、ic不能和virtual、override修饰符同时使用。因为虚函数的本质是实现动态多态性,通过运行时,基类对象所引用的派生对象,达到调用覆盖虚函数的目的。而static函数是通过类名进行调用,与对象无关。 在一个类的继承体系中,可以采用sealed override的方法修饰一个虚函数,禁止后续派生类继续覆盖该虚函数。sealed(密封)不能修饰非虚函数。,【例10-7】用虚函数实现各类人员的显示。 using System; namespace 教材_多态性 class Program static void Main(string args) Person personarray = n

30、ew Person4; /定义Person基类数组 /派生对象可以赋给基类对象 personarray0 = new Student(“320402199005011234“, “李刚“, “男“,“研一“); personarray1 = new Worker(“320402199010101234“, “李魁“, “男“, 6700); personarray2 = new Worker(“320402196312091234“, “彭“, “女“, 2800); personarray3 = new Person(“320402197809091234“, “彭桃“, “女“); for

31、each (Person tp in personarray) tp.Display(); Console.ReadKey(); ,public class Person private string id; public string name; public string Sex get; set; public string Name get return name; set name = value; public string Id get return id; public virtual void Display() /virtual为修饰符,定义虚函数 Console.Writ

32、eLine(“身份证号:0,姓名:1,性别为:2“, Id, Name, Sex); public Person(string pid, string pname, string psex) name = pname; id = pid; Sex = psex; ,public class Student : Person string sgrade; /增加私有字段 public string Sgrade get return sgrade; set sgrade= value; public void UpdateGrade(string pgrade) sgrade = pgrade;

33、 public Student(string pid, string pname, string psex, string pgrade) : base(pid, pname, psex) sgrade = pgrade; public override void Display() /override为修饰符,覆盖基类中的相同虚函数 Console.WriteLine(“身份证号:0,姓名:1,性别为:2,年级为:3“, Id, Name, Sex,Sgrade); ,public class Worker : Person int wage; public int Wage get ret

34、urn wage; set wage = value; public void UpdateWage(int pwage) wage = pwage; public Worker(string pid, string pname, string psex, int pwage) : base(pid, pname, psex) wage = pwage; public override void Display() Console.WriteLine(“身份证号:0,姓名:1,性别为:2,工资为:3“, Id, Name, Sex,wage); ,【例10-8】用虚函数和非泛型集合实现各类人员

35、列表的数据处理。 using System; using System.Collections; /非泛型集合命名空间 using 教材_多态性; namespace 教材_多态性_非泛型集合 class Program static void Main(string args) ArrayList personlist = new ArrayList(); personlist.Add(new Student(“320402199409123456“,“蒋韵“, “女“, “大一“); personlist.Add(new Worker(“320402199312091234“, “李威“,

36、 “男“, 2700); personlist.Add(new Worker(“320402197310011234“, “李香“, “女“, 15000); Console.WriteLine(personlist.Capacity); Console.WriteLine(personlist.Count);,foreach (Object tp in personlist) if (tp.GetType() = typeof(Student) (Student)tp).Sgrade = “大二“; else if (Worker)tp).Wage 3500) (Worker)tp).Wag

37、e=3500; foreach (Person tp in personlist) tp.Display(); Console.ReadLine(); ,10.9 抽象类和抽象方法,1.抽象类 抽象类表示一种抽象的概念,用作派生类的基类,以便所有其派生类具有相同的数据成员和函数成员。抽象类的定义格式为: abstract class 类名 访问权限修饰符 其他修饰符 类成员定义 ; 2.抽象方法 抽象方法的定义格式为: public abstract返回类型 函数名(参数列表) 抽象方法描述的是成员函数的定义,而非实现,所以它没有函数体部分。,关于抽象类和抽象方法必须注意以下几点:,含有抽象方

38、法的类,一定是抽象类。但抽象类并非一定要包含抽象方法,即抽象类中可以定义带实现的方法。 抽象类只能作为派生类的基类,不能被实例化。 不能同时使用Abstract和sealed修饰符声明抽象方法,因为抽象方法需要在派生类中被覆盖,而sealed修饰符禁止方法被覆盖。 抽象方法逻辑上类似于虚方法,可以在派生类中被覆盖。 从抽象类派生出的派生类,若全部覆盖了从抽象类中继承来的抽象方法,该类可以声明为非抽象类,能够实例化,否则,仍然为抽象类。,【例10-9】用抽象图形类实现矩形、圆等图形周长的求解。 using System; namespace 教材_抽象类 class Program static

39、 void Main(string args) square f1 = new Square(20,10); circle f2 = new Circle(30,30,15); Console.WriteLine(f1.Perimeter(); Console.WriteLine(f2.Perimeter(); Console.ReadKey(); public abstract class Figure public abstract float Perimeter(); ,public class Square : Figure private float length,width; pu

40、blic Square(float plength, float pwidth) length = plength; width = pwidth; public override float Perimeter() return 2*(length+width); public class Circle : Figure private float xc, yc, radium; public Circle(float pxc,float pyc,float pradium) xc = pxc; yc = pyc; radium = pradium; public override floa

41、t Perimeter() return (float)(2 * 3.14 * radium); ,10.10委托,委托是C#语言提供的新的引用类型,即委托类型,也称代理类型。在功能上类似于C语言的函数指针,目的是通过委托类型对象去调用相同签名的函数。 委托是从system.delegate中派生的,因此是类型安全的。 采用委托可以实现通用程序的编写。 委托的操作步骤: 1. 定义委托类型 2. 定义委托对象 3. 定义委托方法的实现 4.委托的调用,委托的定义步骤,1. 定义委托类型 委托类型定义格式为: 修饰符 delegate 函数返回类型 委托类型名(函数形参列表) 例如: publi

42、c delegate bool dtest(Person p,string s); 表示定义了一个委托类型,它能代表第一个参数为Person对象,第二个参数为string类型,返回值为bool类型的函数。,委托的定义步骤,2. 定义委托对象 委托对象定义格式为: 委托类型名 委托对象名=new委托类型名(委托方法名); 其中委托方法名可以是某个类的静态方法名,也可以是某个对象的实例方法名。方法的参数类型、返回类型必须与委托类型名的要求一致。 例如: dtest d1=new dtest(Find.FindPeopleById); 表示将委托对象d1代表Find类的FindPeopleById静

43、态方法。具体见下面的例10-10。以后就可以通过调用d1来达到调用FindPeopleById函数的目的。,委托的定义步骤,3. 定义委托方法的实现 委托方法是真正要调用的函数,根据逻辑需要,在类中定义其实现过程。 例如: public static bool FindPeopleById(Person p,string s) return p.Id = s; ,委托的定义步骤,4. 委托的调用 格式为:委托对象名(实参列表); 例如: d1(p1, “320402196312091234“);,委托类型案例,下面结合10-7案例中的类,学习委托类型的使用。 【例10-10】用委托实现各类人员

44、的身份查找和性别查找。 using System; using 教材_多态性;/引用了多态性的类 public delegate bool dtest(Person p,string s); /委托类型必须在类外定义,最好定义在命名空间外 namespace 教材_委托 class Program static void Main(string args) Person personarray = new Person4; personarray0 = new Student(“320402199005011234“, “李刚“, “男“, “研一“); personarray1 = new

45、Worker(“320402199010101234“, “李魁“, “男“, 6700); personarray2 = new Worker(“320402196312091234“, “彭“, “女“, 2800); personarray3 = new Person(“320402197809091234“, “彭桃“, “女“); dtest d1=new dtest(Find.FindPeopleById); /定义委托对象d1 int i = 0;,foreach (Person tp in personarray) i+; /在遍历数组时,找到身份为“3204021963120

46、91234“的人就退出遍历 if (d1(tp, “320402196312091234“) break; personarrayi - 1.Display(); i = 0; d1 = new dtest(Find.FindPeopleBySex); /将委托对象代表FindPeopleBySex函数 foreach (Person tp in personarray) i+; if (d1(tp,“男“) break; /遍历数组时,找到性别为“男“的第一人就退出遍历 personarrayi - 1.Display(); Console.ReadKey(); ,class Find /定

47、义查找类,提供人员的各种查找方法 public static bool FindPeopleById(Person p,string s) return p.Id = s; public static bool FindPeopleBySex(Person p,string s) return p.Sex = s; ,【例10-11】用委托实现学生泛型集合中女同学的查找。 using System; using System.Collections.Generic; using 教材_多态性; namespace 教材_委托_泛型 class Program static void Main(string args) List myList = new List(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1