收藏 分享(赏)

Delphi教学 第02章 面向对象的Pascal(第二部分).ppt

上传人:wspkg9802 文档编号:8034997 上传时间:2019-06-05 格式:PPT 页数:52 大小:330.50KB
下载 相关 举报
Delphi教学 第02章 面向对象的Pascal(第二部分).ppt_第1页
第1页 / 共52页
Delphi教学 第02章 面向对象的Pascal(第二部分).ppt_第2页
第2页 / 共52页
Delphi教学 第02章 面向对象的Pascal(第二部分).ppt_第3页
第3页 / 共52页
Delphi教学 第02章 面向对象的Pascal(第二部分).ppt_第4页
第4页 / 共52页
Delphi教学 第02章 面向对象的Pascal(第二部分).ppt_第5页
第5页 / 共52页
点击查看更多>>
资源描述

1、Delphi 7 程序设计,福州大学至诚学院,第二章 面向对象的Pascal,Delphi的编程语言即Object Pascal是在Pascal的基础上发展起来的,它继承了Pascal语言语法结构严谨和编译代码高效优化等优点。2.1 基本概念 2.2 简单数据类型 2.3 常量、变量 2.4 运算符和表达式 2.5 语句 2.6 构造(结构)数据类型 2.7 函数和过程,2.6 集合类型,2.6.1 -1 集合类型的定义,集合是指具有相同性质且可以相互区分的对象的全体。例如,所有的英文字母可以组成一个集合,全体自然数组成一个集合,某个学校的全体学生组成一个集合,等等。为了表示集合,Object

2、 Pascal 引入了集合类型。,使用集合类型和集合变量之前必须首先进行类型定义和变量声明。 1. 集合与集合类型集合的特点是所包括的各个对象具有某种相同的性质,构成集合的各个对象称为集合的元素,集合的元素是某种简单数据类型的值,这种数据类型称为集合的“基类型”,基类型只能是顺序类型。对于集合有以下几个特点: (1)集合中的元素是互异的,即相同的元素视为同一个元素,集合1,1,2,2与集合1,2是相同的; (2)集合中的元素是无序的,1,2与2,1是同一个集合;,2.6.1-1 集合类型的定义,2. 集合定义 集合的声明格式如下: Type=Set of ; 是用户定义的集合类型名称。表示集合

3、中各元素的类型,可以是字符型、布尔型、枚举型和子界型等顺序类型,但不能是整型、实型和其他的构造类型。,(3)集合中的元素按顺序出现时可以写为子界的形式,如6,7,8,9,11,13可写为69,11,13; (4) 元素与集合的关系是“属于”或“不属于”关系。(in)(5) 集合类型属于构造类型,是由其他的数据类型按照一定的规则构造而成的。Object Pascal规定集合的基类型可能的值不能超过256个,且序号必须在0到255之间,这同时也表明,集合中元素的个数最多是256个。例如,以下定义会显示编译错误: type intset = set of 1300; /集合元素超过256个,2.6.

4、1-1 集合类型的定义,若基类型为枚举或子界类型,则必须先定义该类型,再定义集合类型。例如: typeColors=(Red,Blue,Yellow,White,Black);color=set of Colors;numbers=set of 110;,2.6.1-1 集合类型的定义,3. 集合变量 定义了一个集合则可以声明集合变量,集合变量声明的格式如下:var :; 集合变量的取值称为集合值,它是基类型元素的一个集合,取值范围是包括空集合在内的全体子集。集合值的一般表示格式为方括号括起来的元素序列,元素之间用逗号隔开。, 如下定义了一个集合变量:Type Colors=(Red, Yel

5、low, Blue);BasicColor=set of Colors;var Color1:BasicColor; 则集合变量Color1的取值可以是下列所示的任何集合: ,Red, Yellow, Blue, Red, Yellow, Red, Blue, Yellow, Blue, Red, Yellow, Blue 若集合类型的基类型有n个元素,根据组合可知该类型变量的取值有2n 个,其中包括一个空集合 。,2.6.1-2 集合类型的运算,1. 集合的并、交、差运算 相同类型的集合可以进行并、交、差运算,其值仍是一个该类型的集合。 并运算:集合A、B类型相同,则A和B的并运算记作A+B

6、或B+A,计算结果是由A和B中所有不重复元素组成的集合。 交运算:集合A、B类型相同,则A和B的交运算记作AB或BA,计算结果是由A和B中所有公共元素组成的集合。 差运算:集合A、B类型相同,则A和B的差运算记作A-B,计算结果是由所有属于集合A而不属于集合B的元素组成的集合。利用差运算可以删除集合中的一些元素。 例如,A=1,2,3,B=2,3,4,则: A+B=1,2,3,4; A*B=2,3; A-B=1; B-A=4;,集合类型数据的运算包括两大类,一类是集合的并、交、差运算,其运算结果仍为集合类型值;一类是集合的关系运算,其运算结果是布尔类型值。,2.6. 1-2 集合类型的运算,2

7、. 集合的关系运算集合的关系运算包括类型相同集合之间所进行的相等“=”、不等“”、包含“=”、被包含“B或BA的值为True,否则为Flase。2,31,3,2的值为True。集合的包含运算:如果集合B中的元素都是集合A中的元素,则运算 A=B(称为A包含B)的值为True,否则为Flase。1,3,2=2,3 的值为True。集合的被包含运算:如果集合B中的元素都是集合A中的元素,则运算B=A (称为B被包含在A中)的值为True,否则为Flase。RED,BLUE=RED,GREEN,BLUE的值为True。属于运算:如果数据X与集合A的基类型相同,且被包含在A中,则运算X INA(称为X

8、属于A)的值为True,否则为Flase。RED IN RED,BLUE 的值为True。,2.6. 1-2 集合类型的运算,3. 集合运算符的优先级集合运算符的优先级决定运算时的顺序,运算符的优先顺序如表所示。,集合运算符的优先级,当一个表达式中含有多个集合运算符时,将按优先级由高到低的顺序求值。,2.6. 1-3 集合类型的使用,【例】用集合数据类型求1100之间的所有素数。分析:素数是大于1且除了1 和它本身外,不能被其他任何整数所整除的整数。对于求解1100之间的素数可以从1到100一一判断是否是素数,然后输出素数。也可以采用筛选法,将2100之间的数看成一个集合,从中选出最小数,从中

9、筛选去掉其所有倍数,再找出第二个数将其所有倍数从集合中筛选出去,一直增加到该数为集合中最大数的一半为止,则将集合中所有是其他数的倍数的数全部选出,剩下的即为素数。, 启动Delphi 7.0,新建一个工程,在窗体中添加一个标签。 添加Form1的FormCreate事件代码如下: procedure TForm1.FormCreate(Sender: TObject); typeint100=2100;all=set of int100;,2.6. 1-3 集合类型的使用,Var part:all; i,j:integer; str:string; beginpart:=2100;/集合赋初值

10、for i:=2 to 50 do /双重循环进行筛选for j:=i+1 to 100 doif (j mod i=0) thenpart:=part-j; str:=;j:=0;for i:=2 to 100 do /输出经筛选后剩下的素数if i in part thenbeginj:=j+1;str:=str+inttostr(i)+,;if j mod 5=0 thenstr:=str+chr(13);end;label1.Caption :=str; end;,运行结果如图所示。 其中运用集合的差运算将不是素数的整数从集合中筛选出去。,列举1100之间的所有素数,练习,1 集合表达

11、式1, 2, 3 + 4, 5, 6, 1, 2的值为:(A) 1, 2, 3, 4, 5, 6, 1, 2 (B) 1, 2, 3(C) 4, 5, 6, 1, 2 (D) 1, 2, 3, 4, 5 2 集合表达式m, n, b * a, b, c + m, n, b的值为:(A) m, n, b (B) b(C) a, b, c (D) a, c 3 下列集合表达式中哪一个的值为空集:(A) a z - a, c, B (B) a z + a, c, B(C) a z * a, c, B (D) z * a, c, B 4 下列表达式中哪一个的值为True:(A) a in a, b,

12、c, d(B) 1 12 = 1 5, 6 12(C) 1, 2 + 3, 4 * 3, 5 = 2, 3, 4, 5, 7(D) 12 in 1 10,参考答案:1、A 2、A 3、D 4、B,数组的概念数组是一些具有相同类型的元素按一定顺序组成的序列。其中每个元素由其对应的位置来指定,这个位置就是数组的索引号(又称下标),数组元素与索引号是一一对应的,用户可以通过这个索引号来存取数组的每个元素。数组中的各元素是顺序地安排在内存中一段连续的存储空间中。按照数组在定义时是否确定了元素个数可以将数组分为静态数组和动态数组。,2.6.2 数组,2.6.2-1 静态数组,数组是相同类型的元素按一定顺

13、序组成的序列。数组中的每一个元素都可以通过数组名和惟一一个索引号来存取。在Object Pascal中可以定义数组元素个数一定的数组,即静态数组。根据静态数组的维数可以把数组分为一维静态数组、二维静态数组和多维静态数组。,静态数组在程序初始化时必须分配内存单元,明确其固定的大小和元素的数据类型。,2.6.2-1(1) 定义,1. 一维静态数组 一维静态数组类型声明格式为: Type=arrayof ; 如定义一个数组类型: TypeMyArray=array1100of Real;表示定义了一个有100个元素的数组类型,元素下标从1到100,每个数组元素都是Real类型,数组类型标识符为MyA

14、rray。,2.6.2-1(1) 静态数组定义,数组类型标识符可以是任何合法的标识符。Object Pascal 允许下标的类型为整数类型、字符类型、布尔类型、子界类型、枚举类型等。而元素类型可以为任意的数据类型,但在同一数组中,所有元素的数据类型必须相同。对于用户定义的数据类型作为下标类型,在使用之前必须声明。例如可以进行如下定义: TypeColor=(red,green,blue);Number=0100;MyArray=ArrayColor of Integer;ColorArray=ArrayNumber of Color;以上就定义了一个以MyArray为标识的数组类型,其元素下标

15、分别为 red、green和blue,每个数组元素都是Integer类型。,2.6.2-1(1)静态数组定义,经过数组类型声明之后才可以定义数组变量。就像定义整型或实型变量一样,通过变量说明语句定义变量,例如:var A1,A2:MyArray; /A1red;A1green; A1blue上面定义了两个数组变量A1和A2,它们的数据类型是MyArray;也可以把数组类型的定义和数组变量的定义组合起来,以便简化代码,例如:var A1,A2:Array1100 of real;数组元素的访问: 要访问数组中的元素,可以用数组名加方括号,方括号内是元素的下标值,如A13 、A220等。方括号内的

16、下标值必须符合数组类型的定义,其类型必须与下标类型一致,其值在下标取值范围。另外,下标可以是表达式。 Eg: x=4;y=16; A2x+y,2.6.2-1(1)静态数组定义,3. 二维及多维静态数组二维数组是指一个一维数组中的元素类型本身又是一个一维数组,声明二维数组的一般形式为: Type=Array,of ; 例如: TypeRealArray=Array120,1100of Real;以把二维数组看做是一个矩阵,其中下标1是行,下标2是列,这样要 访问二维数组的元素可以写成array12,3,即访问第2行第3列的元素。对于多维数组可以使用循环语句给数组赋值,例如: var Col,Ro

17、w : Integer; for Col :=1 to 20 dofor Row :=1 to 100 do RealArrayCol,Row:=0; ,2.6.2-1(1)静态数组定义,多维静态数组的一般格式为: Type =Array, , ,of 一般情况,用户的数组不超过三维数组,用到三维以上的很少,但Object Pascal允许定义任意维数的数组。 静态数组通过下标类型、维数明确了数组的大小。动态数组使用时没有说明数组的大小,只是在程序设计中为程序动态地开辟存储空间。,2.6.2-1(1)静态数组使用,随机产生5个小于10的整数,放入一维数组A中,求出该组数据的累加和及平均值,并输

18、出.运行结果如图示:,varForm1: TForm1;a:array15 of integer; /定义全局变量 procedure TForm1.Button1Click(Sender: TObject); var i:integer; beginlabel1.Caption :=;randomize;for i:=1 to 5 dobeginai:=trunc(random(10);label1.Caption :=label1.Caption +inttostr(ai)+ ;end; end;,procedure TForm1.Button2Click(Sender: TObject)

19、; var i,sum:integer;avg:real; beginsum:=0;for i:=1 to 5 dosum:=sum+ai;avg:=sum/5;label2.Caption :=累加和为:+inttostr(sum)+,平均值为:+floattostr(avg); end;,2.6.2-2 动态数组,静态数组在程序初始化时必须明确其固定的大小和类型。然而在有些时候,希望在数组使用的时候再分配内存,这种数组称为动态数组。,动态数组是指在定义数组时不说明数组元素个数而是在程序运行时确定。1. 一维动态数组 一维动态数组类型声明格式为: Type=array of ; 也可在声明变

20、量时直接声明一维动态数组: var:array of ; 如下代码: var Myarray:array of integer; 就声明了一个变量名为Myarray的元素类型为一维整型的动态数组。,2.6.2-2 定义,2.6.2-2 动态数组定义,一维动态数组的声明中没有给出数组的下标类型,因此就可以声明一个不指定元素个数的数组。在程序设计中,通过调用标准过程Setlength来明确动态数组的大小。 var A: array of real; /定义一个名为A的动态数组 begin A2:=1.52; /错误,没有明确数组大小前是不能对数组赋值的 setlength(A,30); /设置动态

21、数组长度为30,下标从0到29 A2:=1.52; /正确 end;,2.6.2-2动态数组定义,2. 多维动态数组动态数组也可以是多维的,要声明多维数组,可以采用递归的方式来定义。可以在一维数组的array of后面再附加上array of : Type=array of array of array of ; var :;当然,也可以在声明变量时直接声明多维动态数组,如下定义: var :array of array of array of ;,如下代码定义了一个变量名为A的元素数据类型为实型的二维动态数组: var A:array of array of real; 相应地,如果要设定一

22、个45的二维动态数组可将setlength函数写成:setlength(A,4,5);,2.6.3 记录类型,在解决现实问题中,常需要把一些数据类型不同的数据集中在一起,并作为一个整体处理。例如学生登记表一般包含学号、姓名、性别、年龄、家庭地址多条信息,每一个学生的情况可以看成一个整体,就像数据库中的一个记录一样。记录类型( record )是由不同类型的元素组成的一种结构,这些元素称为域。 语法(记录类型的定义):type 记录类型标识符= Record域名1: 类型;域名2: 类型;. . .域名n: 类型end;,例:type Student=Record /定义记录类型Student

23、Num:160;Name:string;Birthday:TdateTimeend;var Student1,Student2:Student;,2.6.3 记录类型,语法(记录域访问格式):记录变量名.域名例: Student1. Num=1; 和Student1.name=Tony; 语法(with语句):with 记录变量名表 do 语句with后如果包含多个变量名,各变量名之间须用逗号隔开,do 后可以是单条语句,也可以是复合语句(用begin和end括起来),在这些语句中,对域的访问不需要再加记录的变量名。 例:with student1 dobeginnum:=1;name=Ton

24、yEnd;,2.6.5 可变类型,变体类型是Delphi 中提供了一种功能强大的数据类型。 变体类型的作用在于能在运行期间动态的改变数据类型。 Variant变量在声明时,总是被初始化为一个特殊值Unassigned,表明Variant未被赋值。 当Variant为的值为Null时,表明变量未知或数据已丢失。 例:Var V,V1:Variant; BeginV:=Delphi is Great!;/此时变量是一个字符串。V:=4;/此时变量是一个整型数据。V:=1.5;/此时变量是一个浮点数。V:=true;/此时变量是一个布尔型量。 End;,2.7 函数和过程,函数和过程是实现一定功能的

25、语句块,是程序中的特定功能单元。可以在程序的其他地方被调用,也可以进行递归调用。函数和过程的区别在于函数有返回值,而过程没有返回值。 2.7.1 函数和过程的声明 函数和过程在使用前必须进行声明。 1函数的声明 具体形式如下: function ():;,2.7 函数和过程,函数的定义是在程序的implementation部分,具体形式如下: function ():; varbegin:= /也可以用Result系统保留字代替 end; 在begin与end之间是在函数调用时实现特定功能的一系列语句。函数值的返回有两种方式: 将返回值直接赋给函数名。 将返回值赋给Result。,2.7 函数

26、和过程,【例】求两个数中的最大数。 function Max1(a,b: integer):integer; /两个形参为整型值a、b,函数返回值为整型 var m: Integer; beginif ab thenm:= aelsem:= b;Max1:= m; /或result := m; end;,2.7 函数和过程,2过程的声明 过程的声明与函数类似,所不同的是使用的保留字不同,而且少了一个返回值类型; 具体形式如下: procedure (); 过程的定义是在程序的implementation部分,具体形式如下: procedure ();begin end;,2.7 函数和过程,【

27、例】显示一行num个星号*。procedure ShowStar(num:Integer);vari: Integer;s:String;begins:= ;for i:=1 to num dos:= s+*;ShowMessage(s);end;,2.7 函数和过程,2.7.2 重载函数和过程 所谓重载,是指在同一程序内给不同的函数或过程取同一个名称。重载函数必须用指令字overload来进行说明。 下面的两个函数就是重载函数: function Max1(a:Integer;b:Integer):Integer;overload; /求两个整数的最大值 function Max1(a:Re

28、al;b:Real):Real;overload; /求两个实数的最大值 下面两条语句就调用了不同的函数: Max1(3.7,4.6); /调用的是第二个重载函数 Max1(3,4); /调用的是第一个重载函数,2.7 函数和过程,2.7.3 参数 1形参与实参 函数或过程的声明和定义时参数列表中的参数称为形式参数,简称形参;而函数或过程调用时参数列表中的参数称为实在参数,简称实参。 2数值参数、变量参数和常量参数 (1) 数值参数 在调用函数或过程时,数值参数在运行过程中只改变其形参的值,不改变其实参的值,即形参不会影响原来实参的值。Eg: Var x:integer; procedure

29、proc1(x:integer); X:=10 begin Proc1(x); x:=x+5;end; 则执行proc1(x)后,主程序中的x=10,过程体中的x=15,(2) 变量参数 如果用户想改变传递的参数值,就需要使用变量参数,即在被调用程序的参数表中的形参前加上保留字var。Var x:integer; procedure proc2(var x:integer); X:=10 begin Proc2(x); x:=x+5;end; 则执行proc2(x)后,主程序中的x=15,过程体中的x=15,2.7 函数和过程,2.7 函数和过程,(3) 常量参数如果当过程或函数执行时要求不改

30、变形参的值,最保险的办法是使用常量参数。在参数表的参数名称前加上保留字const可以使一个形参成为常量参数。使用常量参数代替数值参数可以保护用户的参数,使用户在不想改变参数值时不会意外地将新的值赋给这个参数。 Var x:integer; procedure proc3(const x:integer); X:=10 begin Proc3(x); x:=x+5; /编译出错end;,2.7 函数和过程,2.7.4 作用域在Object Pascal中,根据变量的作用域,可将变量分为:全局变量和局部变量。所谓变量的作用域,是指变量的有效范围。全局变量在整个程序中都有效,其作用域为整个程序;局部

31、变量只在声明它的函数和过程中有效,其作用域只限于该函数或过程本身。,2.7 函数和过程,例: type var Form1: TForm1; /全局变量Form1 implementation $R *.dfm procedure TForm1.FormCreate(Sender: TObject); var m,n:Integer; /局部变量m,n Form1:Tform1; (*局部变量Form1,与上面的全局变量同名,在过程TForm1.FormCreate中局部变量起作用。*),2.7 函数和过程,2.7.5 函数和过程的调用 1函数和过程的调用 (1) 函数的调用 函数调用的一般形

32、式为: () 函数的调用往往是将返回值赋给某个变量或参与运算。例如调用上例,将其返回值赋给变量x的语句为: x:=Max1(3,6); (2) 过程的调用 过程的调用的一般形式为:(); 其中的实参可以是常量、变量或表达式,但实参的个数和类型与形参完全匹配,即个数相同、类型一致。例如:调用上例的过程ShowStar的语句为: ShowStar(20);,2.7 函数和过程,2函数和过程的递归调用递归调用是指子程序(函数或过程)调用子程序自身。用递归解决问题出自这样一种思维方法:把一个问题分解成若干个子问题,这些子问题的求解方法与原问题的求解方法一样,继续这种分解,直到问题的规模足够小时,能直接

33、得出答案,然后再逐层回溯,组合这些子问题,以得到原问题的解。用递归方法写出的程序较简短,容易理解,但递归的程序执行效率比较低。 【例】求s =1+2+3+ +n。 这个求和问题可以这样理解:1 当n=1时 f(n)= f(n-1)+n 当n1时,Function f(n:integer):integer Beginif n=1 thenresult:=1;else result:=f(n-1)+n/调用函数自身 End;,练习,1 设有一个自定义函数声明如下: function fun(x, y, z : integer) : integer; beginfun := z y div x; e

34、nd; 则表达式fun(fun(2, 4, 6), 6, 8)的值是多少?2 设有一个自定义过程声明如下: procedure p(x : integer; var y : integer); beginx := x y;y := y + x; end; 执行下述程序段: a := 10; b := 4; p(a, b); p(a mod b, a); 则a, b的值分别是什么?,参考答案:1、72、a=0,b=10,2.8 习题及上机练习,1Object Pascal语言中有哪些常用的数据类型?变量在使用前必须先定义,如何定义各种数据类型的变量? 2. 简述Object Pascal中标识符

35、的命名应遵循哪些规则。 3. Object Pascal中提供了哪些类型运算符,在表达式中其优先级从高到低如何排列。 4注释语句有哪几种形式? 5条件语句有哪几种形式?它们在什么情况下适用。 6循环语句有哪几种形式?break语句与continue语句有何异同。 7如何声明、定义和调用函数和过程。 8什么是重载?如何进行重载函数和过程。 9什么是变量的作用域?根据变量的作用域,可将变量分为哪几类。,上机练习题,1、求整数各位数字【练习题目】利用本章学习的算术运算符和算术表达式,编写一个程序,实现下面的功能:输入一个任意4位整数,计算千位、百位、十位和个位上的数字。程序设计界面和程序运行界面如图

36、所示。程序运行时,输入任意整数(4位整数),单击按钮【个位数字】,将显示个位数字,单击按钮【十位数字】,将显示十位数字,其它依此类推。,上机练习题,2、计算数学中常量的值 【练习题目】编一个程序按下列公式求e的值(要求精度达到1e-5)。程序运行时,单击【计算】按钮,将计算并显示符合给定精度的值,程序的设计界面及运行界面如图所示。,上机练习题,3、数字灯谜 【练习题目】有算式:,A、B、C、D为非负一位数字,要求找出满足以上算式的A、B、C、D。,上机练习题,4、搬砖问题【练习题目】36块砖,男搬4块,女搬3块,两个小孩抬1块,要求一次搬完,且男人、女人和小孩都必须参加,问男、女、小孩各需要多

37、少人。程序运行界面如下:,上机练习题,5、求数组的最大数及下标 【练习题目】随机产生5个两位正整数并存放到一维数组中,然后找出其中的最大值及其下标。程序设计界面和程序运行界面如图所示。,上机练习题,6、验证哥德巴赫猜想【练习题目】德国著名数学家哥德巴赫提出:任何一个大于等于6的偶数都可以表示为两个素数之和。请编写程序验证这一猜想。程序运行时,在第一个编辑框里输入任意大于等于6的偶数,单击【验证】按钮,则在另一编辑框里显示两个符合要求的素数。程序的设计界面和程序运行界面如图所示。要求判断某数是否为素数用一个函数来实现。,上机练习题,7、摸彩球【练习题目】商场搞促销活动,顾客凭购物发票摸彩球。在装

38、球的小箱子里连续摸三次,每次摸的球都要放回去,如果三次摸的球颜色各不相同,那么该顾客就中奖了。假设箱子里一共只有3种颜色的球,分别为红色球(red)、绿色球(green)和蓝色球(blue),请编写程序找出不同的摸奖办法,并显示摸出的球。程序设计界面和程序运行界面如图所示。要求用枚举类型实现。,上机练习题,8、裁判评分程序【练习题目】编写一个裁判评分程序。共设有裁判6人,评分满分为100分,除去一个最高分,除去一个最低分,剩余的评分的平均值即为选手得分。要求:编写一个过程求选手得分,得分通过参数返回给调用过程。程序运行界面如下图所示:,上机实现题: (以下各题n值由用户输入,且n值=1001-4题) 1. 求12+22+32+42+n2 2. 求1-3+5-7+(-1)n+1(2n-1) 3. 求1+(1+2)+(1+2+3)+(1+2+3+n)5. 求n+nn+nnn+nnnn+nnnnn(1=n=9,最大数值为5位数),4. 求,

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

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报