C++程序的结构特性

嵌入式技术

1338人已加入

描述

C语言的局限

C++的特点

C++的程序特征

C++程序的结构特性

C++程序的编辑、编译和运行

C++对C的补充

C++的特点

C++继承了C的优点,并有自己的特点,主要有:

1、全面兼容C,C的许多代码不经修改就可以为Cpp所用,用C编写的库函数和实用软件可以用于Cpp。

2、用C++编写的程序可读性更好,代码结构更为合理,可直接在程序中映射问题空间结构。

3、生成代码的质量高,运行效率高。

4、从开发时间、费用到形成软件的可重用性、可扩充性、可维护性和可靠性等方面有了很大提高,使得大中型的程序开发项目变得容易得多。

5、支持面向对象的机制,可方便的构造出模拟现实问题的实体和操作。

C++的程序特征

    例1.1 输出一行字符:“This is a C++ program.”。

    程序如下:


#include  //包含头文件iostream
using namespace std; //使用命名空间std
int main( )
{
    cout<<″This is a C++ program.″;
    return 0;
}
      在运行时会在屏幕上输出以下一行信息: This is a C++ program.

用main代表“主函数”的名字。每一个C++程序都必须有一个 main 函数。main前面的int的作用是声明函数的类型为整型。程序第6行的作用是向操作系统返回一个零值。如果程序不能正常执行,则会自动向操作系统返回一个非零值,一般为-1。

函数体是由大括号{}括起来的。本例中主函数内只有一个以cout开头的语句。注意C++所有语句最后都应当有一个分号。

再看程序的第1行“#include

”,这不是Cpp的语句,而是Cpp的一个预处理命令,它以“#”开头以与Cpp语句相区别,行的末尾没有分号。

#include 是一个“包含命令”,它的作用是将文件iostream的内容包含到该命令所在的程序文件中,代替该命令行。文件iostream的作用是向程序提供输入或输出时所需要的一些信息。

iostream是i-o-stream3个词的组合,从它的形式就可以知道它代表“输入输出流”的意思,由于这类文件都放在程序单元的开头,所以称为“头文件” (head file)。在程序进行编译时,先对所有的预处理命令进行处理,将头文件的具体内容代替#include命令行,然后再对该程序单元进行整体编译。

程序的第2行“using namespace std;”的意思是“使用命名空间std”。Cpp标准库中的类和函数是在命名空间std中声明的,因此程序中如果需要用到Cpp标准库(此时就需要用#include命令行),就需要用“using namespace std;”作声明,表示要用到命名空间std中的内容。

在初学C++时,对本程序中的第1,2行可以不必深究,只需知道:如果程序有输入或输出时,必须使用“#include

”命令以提供必要的信息,同时要用“using namespace std;”,使程序能够使用这些信息,否则程序编译时将出错。

    例1.2 求a和b两个数之和:

 


// 求两数之和 (本行是注释行)
#include  //预处理命令
using namespace std; //使用命名空间std
int main( ) //主函数首部
{ //函数体开始
    int a,b,sum; //定义变量
    cin>>a>>b; //输入语句
    sum=a+b; //赋值语句
    cout<<″a+b=″<
      本程序的作用是求两个整数a和b之和sum。     

第1行“//求两数之和”是一个注释行,Cpp规定在一行中如果出现“//” ,则从它开始到本行末尾之间的全部内容都作为注释。

 

    例1.3 给两个数x和y, 求两数中的大者:

 


#include  //预处理命令
using namespace std;
int max(int x,int y) //定义max函数,函数值为整型,形式参数x, y为整型
{ //max函数体开始
    int z; //变量声明,定义本函数中用到的变量z为整型
    if(x>y) z=x; //if语句,如果x>y, 则将x的值赋给z
    else z=y; //否则,将y的值赋给z
    return(z); //将z的值返回,通过max带回调用处
} //max函数结束
int main( ) //主函数
{ //主函数体开始
    int a,b,m; //变量声明
    cin>>a>>b; //输入变量a和b的值
    m=max(a,b); //调用max函数,将得到的值赋给m
    cout<<″max=″<
      本程序包括两个函数:主函数main和被调用的函数max。     程序运行情况如下:

 

18 25 (输入18和25给a和b)

max=25 (输出m的值)

    注意输入的两个数据间用一个或多个空格间隔,不能以逗号或其他符号间隔。     

在上面的程序中,max函数出现在main函数之前,因此在main函数中调用max函数时,编译系统能识别max是已定义的函数名。如果把两个函数的位置对换一下,即先写main函数,后写max函数,这时在编译main函数遇到max时,编译系统无法知道max代表什么含义,因而无法编译,按出错处理。     

为了解决这个问题,在主函数中需要对被调用函数作声明。上面的程序可以改写如下:


#include 
using namespace std;
int max(int x,int y); //对max函数作声明
int main( )
{
    int a,b,c;
    cin>>a>>b;
    c=max(a,b); //调用max函数例1.3 给两个数x和y, 求两数中的大者。
    cout<<″max=″<y) z=x;
    else z=y;
    return(z);
}
      只要在被调用函数的首部的末尾加一个分号,就成为对该函数的函数声明。函数声明的位置应当在函数调用之前。

 

C++程序的结构特性

    一个面向对象的C++程序一般由类的声明和类的使用两大部分组成。     

类的使用部分一般由主函数及有关子函数组成。

    典型的C++程序结构:

 


#include 
//类的声明部分
class A{
    int x,y,z;
    ……
    fun( ){……}
    ……
};
//类的使用部分
int main()
{
    A a;
    ……
    a.fun();
    return 0;
}
      在C++程序中,程序设计始终围绕“类”展开。通过声明类,构建了程序所要完成的功能,体现了面向对象程序设计的思想。

 

C++程序的编辑、编译和运行

    C++源程序文件的扩展名为.CPP,可以用多种编译器编辑、编译和运行。

    C++对C的补充:

1、注释与续行

注释符:“/*”和“*/” 或“//” 。

    Cpp新增了注释语句,它由“//”开始,到行尾结束。     

例如:


X = y + z; /*This is a comment */


X = y + z; //This is a comment
 

 

续行符:“”(反斜杠)。作用是当一个语句太长时可以用该符号把它分段写在几行中。
例:

 


cout << ‘
’ << “x=” << x << “y=” << y << “z=” << z
 << “u=” << u << “v
=” << v << “w=” << w << endl;
 

 

2、输入输出流

    C中I/O操作出现的问题:


int i;
float f;
scanf(“%f”,i);
printf( “%d”,d);
      Cpp中使用更安全更方便的方法:

int i;
float f;
cin >> i;
cout << f;
      cout和cin分别是C++的标准输出流和输入流。Cpp支持重定向,但一般cout指的是屏幕, cin指的是键盘。     

操作符“<<”和“>>”除了具有C语言中定义的左移和右移的功能外,在这里符号“<<”是把右方的参数写到标准输出流cout中;相反,符号“>>”则是将标准输入流的数据赋给右方的变量。

 

    例1.4 一个完整的C++程序:

 


#include 
int main()
{
    char name[20];
    cout << "Hello, your name:";
    cin >> name;
    cout << name;
    return 0;
}
      注意:

 

程序中必须包含头文件iostream.h

cin和>>,cout和<<配套使用

cin可以输入多个数据,但要用空白符隔开(tab,空格,回车)   

    如:cin >> a >> b >> c;

换行符:‘ ’或endl

    如:cout << “x=” << x << endl; cout << “x=” << x << ‘ ’;

使用cout和cin时,也可以对输入和输出的格式进行控制,比如可用不同的进制方式显示数据,只要设置转换基数的操作符dec、hex和oct即可。

    例1.5 操作符dec、 hex和oct的使用:

 


#include
void main()
{
    int x=25;
    cout << hex << x << ' ' << dec << x << ' ' << oct << x << '
';
}
      输出结果为:19 25 31

 

3、灵活的变量说明

    定义变量的位置:

    在程序中的不同位置采用不同的变量定义方式,决定了该变量具有不同的特点。变量的定义一般可有以下三种位置:

(1) 在函数体内部     

在函数体内部定义的变量称为局部变量,这种局部变量只在进入定义它的函数体时起作用,离开该函数体后该变量就消失(被释放),即不再起作用。因此,不同函数体内部可以定义相同名称的变量,而互不干扰。

(2) 形式参数     

当定义一个有参函数时,函数名后面括号内的变量,统称为形式参数。

(3) 全局变量     

在所有函数体外部定义的变量,其作用范围是整个程序,并在整个程序运行期间有效。

在C语言中,全局变量声明必须在任何函数之前,局部变量必须集中在可执行语句之前。

Cpp中的变量声明非常灵活,它允许变量声明与可执行语句在程序中交替出现。

    例如:


f( )
{
    int i;
    i=10;
    int j;
    j=25;
    // …
}
float fun(int x,int y)
{
    for(int i=0;i<10;i++)
    {
        int sum=0;
        sum=sum+i;
        cout<<“sum=”<
 

 

4、结构、联合和枚举名

    在C++中,结构名、联合名、枚举名都是类型名。在定义变量时,不必在结构名、联合名或枚举名前冠以struct、union或enum。     

例如:


enum boole{FALSE,TRUE};
struct string{
    char *string;
    int length;
};
union number{
    int i;
    float f;
};
      在传统的C中,定义变量时,必须写成:

enum boole done;
struct string str;
union number x;
      但是,在C++中,可以说明为:

boole done;
string str;
number x;
 

 

5、函数原型

    C语言建议编程者为程序中的每一个函数建立原型,而Cpp要求为每一个函数建立原型,以说明函数的名称、参数类型与个数,以及函数返回值的类型。     

其主要目的是让C++编译程序进行类型检查,即形参与实参的类型匹配检查,以及返回值是否与原型相符,以维护程序的正确性。     

例如:


int sum(int a,int b);   //是函数sum的原型
 

 

函数原型语法的一般形式为:返回类型 函数名(参数表);

函数原型是一条语句,它必须以分号结束。

    例1.6 函数原型的说明:

 


#include
void write(char *s);
void main()
{write("Hello,world!");}
void write(char *s)
{cout<
      在程序中,要求一个函数的原型出现在该函数的调用语句之前。

 

    说明:

函数原型的参数表中可不包含参数的名字,而只包含它们的类型。例如:long Area(int ,int);

函数定义由函数首部和函数体构成。函数首部和函数原型基本一样,但函数首部中的参数必须给出名字而且不包含结尾的分号。

Cpp的参数说明必须放在函数说明后的括号内,不可将函数参数说明放在函数首部和函数体之间。这种方法只在C中成立。

主函数不必进行原型说明,因为它被看成自动说明原型的函数。

原型说明中没有指定返回类型的函数(包括主函数main),Cpp默认该函数的返回类型是int

如果一个函数没有返回值,则必须在函数原型中注明返回类型为void,主函数类似处理。

如果函数原型中未注明参数,Cpp假定该函数的参数表为空(void)。

6、const修饰符

在C中,习惯使用#define定义常量。

一般格式: #define 宏名 常数     如:


#define PI 3.14
…………
s = 2 * PI * r;
…………
 

 

C++利用const定义正规常数

    一般格式:const 数据类型标识符 常数名=常量值;     

采用这种方式定义的常量是类型化的,它有地址,可以用指针指向这个值,但不能修改它。

    说明:

1、const必须放在被修饰类型符和类型名前面

2、数据类型是一个可选项,用来指定常数值的数据类型,如果省略了该数据类型,那么编译程序认为它是 int 类型。     

如:const int a=10; 表示定义了一个初始值为10的整型常量,它在程序中不可改变,但可用于表达式的计算中。

    例2.6 #define的不安全性:

 


#include "iostream.h"
main()
{
    int a=1;
    #define T1 a+a
    #define T2 T1-T1
    cout<<"T2 is "<
      但实际的输出是:T2 is 2。     

const作用与#define相似,但消除了#define的不安全性。     

如果用const取代了两个#define,就不会引起这个错误。

#include
int main()
{
    int a=1;
    const T1=a+a;
    const T2=T1-T1;
    cout <<"T2 is"<
 

 

    const可以与指针一起使用:

(1)指向常量的指针:一个指向常量的指针变量。

    例如:


const char* pc=“abcd”;  //声明指向常量的指针
pc[3]=‘x’;  //错误


pc=“efgh”;  //允许
 

 

(2)常指针:把指针本身,而不是它指向的对象声明为常量。

    例如:


char* const pc=“abcd”;  //常指针
pc[3]=‘x’;  //合法
pc=“efgh”;  //出错
      创建一个常指针,就是创建一个不能移动的固定指针,但是它所指的数据可以改变。例如:

 

(3)指向常量的常指针:这个指针本身不能改变,它所指向的值也不能改变。

    要声明一个指向常量的常指针,二者都要声明为const。     

例如:


const char* const pc=“abcd”;    //指向常量的常指针
pc[3]=‘x’;  //出错
pc=“efgh”;  //出错
      这个语句的含义是:声明了一个名为pc的指针变量,它是一个指向字符型常量的常指针,用“abcd”的地址初始化该指针。

 

    说明:

(1). 如果用const定义的是一个整型常量,关键词int可以省略。所以下面的两语句是等价的  

const int bufsize=200;
const bufsize=200;

 

(2). 常量一旦被建立,在程序的任何地方都不能再更改。

(3). 与#define定义的常量有所不同,const定义的常量可以有自己的数据类型,这样C++的编译程序可以进行更加严格的类型检查,具有良好的编译时的检测性。

(4). 函数参数也可以用const说明,用于保证实参在该函数内部不被改动,大多数C++编译器能对具有const参数的函数进行更好的代码优化。   

    例如:通过函数i_Max求出整型数组a[200]中的最大值,函数原型应该是:int i_Max(const int* ptr);     

这样做的目的是确保原数组的数据不被破坏,即在函数中对数组元素的操作只许读,而不许写。调用时的格式可以是:i_Max(a);

7、void型指针

    void 通常表示无值,但将void作为指针的类型时,它却表示不确定的类型。     

这种void型指针是一种通用型指针,也就是说任何类型的指针值都可以赋给void类型的指针变量。     

例如下面的程序段:


void pa;    //错误,不能声明void类型的指针变量
void* pc;   //正确,可以声明void类型的指针
int i=456;
char c=‘a’;
pc=&i;
pc=&c;
      void型指针可以接受任何类型的指针的赋值,但对已获值的void型指针,对它在进行处理,如输出或传递指针值时,则必须进行强制类型转换,否则会出错。

#include 
main()
{
    void *pc;
    int i=456;
    char c='a';
    pc=&i;
    cout<<*(int *)pc<
 

 

8、内联函数

    调用函数时系统要付出一定的开销,用于信息入栈出栈和参数传递等。特别是对于那些函数体较小但调用又较频繁的函数,计算机的开销相对就比较可观。     

在C语言中,用宏替换,可解决这个问题。例如,有如下的函数:


add(int x,int y)
{
    return x+y;
}
      用宏替换时,上面的函数功能可写为:

#define add(x,y) x+y
      C++引进了内联函数(inline function)的概念。     

宏替换实质上是文字替换。内联函数与一般函数不同的是,在进行程序的编译时,编译器将内联函数的目标代码作拷贝并将其插入到调用内联函数的地方。

 

    例1.7 内联函数的使用:

 


#include "iostream.h"
inline double circle(double r)
{return 3.1416*r*r;}
int main()
{
    for(int i=1;i<=3;i++)
        cout<<"r="<y)?x:y << endl;
    else
        cout << "the smaller value is: " << (x
 

 

10、函数重载

(1) 什么是函数重载

    函数重载是指一个函数可以和同一作用域中的其他函数具有相同的名字,但这些同名函数的参数类型、参数个数不同。如:


#include 
void whatitis(int i)
{ cout<<"this is integer"<
      在本例中定义了两个名称都叫whatitis的函数,但它们的形参类型不同。因此,这两个函数就是重载函数。

 

(2) 为什么要使用函数重载

    在原有C语言中,每个函数必须有其唯一的名称,这样的缺点是所有具有相同功能、而只是函数参数不一样的函数,就必须用一个不同的名称.     

而C++中采用了函数重载后,对于具有同一功能的函数,如果只是由于函数参数类型不一样,则可以定义相同名称的函数。

(3) 匹配重载函数的顺序

    由于重载函数具有相同的函数名,在进行函数调用时,系统一般按照调用函数时的参数个数、类型和顺序来确定被调用的函数。     

具体来说,按以下三个步骤的先后次序找到并调用那个函数:

(1)寻找一个严格的匹配,即:调用与实参的数据类型、个数完全相同的那个函数。

(2)通过内部转换寻求一个匹配,即:通过(1)的方法没有找到相匹配的函数时,则由C++系统对实参的数据类型进行内部转换,转换完毕后,如果有匹配的函数存在,则执行该函数。

(3)通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,就调用那个函数。即:在函数调用处由程序员对实参进行强制类型转换,以此作为查找相匹配的函数的依据。

    例1.8 重载例子:

 


#include 
void print(double d)
{ cout<<"this is a double "<
 

 

    例 重载例子:

    编写一个程序,用来求两个整数或3个整数中的最大数。如果输入两个整数,程序就输出这两个整数中的最大数,如果输入3个整数,程序就输出这3个整数中的最大数。


#include 
using namespace std;
int main( )
{
    int max(int a,int b,int c); //函数声明
    int max(int a,int b); //函数声明
    int a=8, b=-12, c=27;
    cout<<"max(a,b,c)="<
      如果希望在局部变量的作用域内使用同名的全局变量,可以在全局变量加上“::”,此时::avar代表全局变量avar

#include 
int avar=10;
main()
{
int avar;
avar=25;
cout<<"local avar ="<age=23;
    cout<<"
"<name<<" "<age;
    delete p;
    return 0;
}
      与C的内存动态分配和释放操作(malloc和free)相比,C++提供的动态分配有以下优点:

 

(1) new和delete 操作自动计算需要分配和释放类型的长度。这不但省去了用sizeof计算长度的步骤,更主要的是避免
了内存分配和释放时因长度出错带来的严重后果;

(2) new操作自动返回需分配类型的指针, 无需使用强制类型转换;

(3) new操作能初始化所分配的类型变量。

(4) new和delete都能可以被重载,允许建立自定义的内存管理法。

    对使用new和delete的几点说明:

(1)用new分配的空间,使用结束后应该用delete显示的释放,否则这部分空间将不能回收而变成死空间。

(2)使用new动态分配内存时,如果没有足够的内存满足分配要求, new将返回空指针(NULL)。因此通常要对内存的动态分配是否成功进行检查。

    例1.11 对内存的动态分配是否成功进行检查:

 


#include 
main()
{
    int * p;
    p=new int;
    if(!p){
        cout<<"allocation failure
";
        return 1;
    }
    *p=20;
    cout<<*p;
    delete p;
    return 0;
}
 

 

(3) 使用new可以为数组动态分配内存空间这是需要在类型后面缀上数组大小。其语法形式为:

指针变量=new 类型名 [下标表达式]; 如:int *pi=new int[2][3][4]; 其中第一维的界值可以是任何合法的表达式,如:int i=3; int *pi=new int[ i ][2][3]; 例如:int *pi=new int[10]; 这时new为具有10个元素的整型数组分配了内存空间,并将首地址赋给了指针pi。 使用new为多维数组分配空间时,必须提供所有维的大小,

(4) 释放动态分配的数组存储区时,可使用delete运算符,其语法形式为:delete [ ]指针变量; 无须指出空间的大小,但老版本的Cpp要求在delete的方括号中标出数字,以告诉Cpp要释放多少个元素所占的空间。例如:delete []pi; delete [10]pi;

(5) new可在为简单变量分配内存空间的同时,进行初始化。这时的语法形式为:指针变量=new 类型名(初始值列表)

    例 1.12 new为简单变量分配内存空间的同时,进行初始化:

 


#include 
int main()
{
    int *p;
    p=new int(99); // 动态分配内存,并将99作为初始值赋给它
    if (!p)
    {
        cout<<"allocation failure
";
        return 1;
    }
    cout<<*p;
    delete p;
    return 0;
}
 

 

    例 1.13 给数组分配内存空间的例子。

 


#include 
main()
{
    double *s;
    s=new double[10];
    if(!s){
        cout<<"alocation failure
";
        return 1;
    }
    for(int i=0;i<10;i++)
        s[i]=100.00+2*i;
    for(int i=0;i<10;i++)
        cout<
 

 

15、引用

(1) 引用的概念

    引用就是某一变量(目标)的一个别名,这样对引用的操作就是对目标的操作。     

引用的声明方法: 类型标识符 &引用名=目标变量名;


int a;
int &ra=a; //定义引用ra,它是变量a的引用,即别名
 

 

    说明:

(1) &在此不是求地址运算,而是起标识作用。

(2) 类型标识符是指目标变量的类型。

(3)声明引用时,必须同时对其进行初始化。

(4)引用声明完毕后,相当于目标变量名有两个名称。

(5)声明一个引用,不是新定义了一个变量,系统并不给引用分配存储单元。

    例1.15 引用的使用:

 


#include 
void main()
{
    int i;
    int &j=i;
    i=30;
    cout<<"i="<
      结果:

i=30 j=30
i=80 j=80
Address of oxfff4
Address of oxfff4
 

 

    例1.16 使用引用可以简化程序:

 


#include
main()
{
    int i=15;
    int* iptr=&i;
    int & rptr=i;
    cout<<" i is "<
      运行结果:

i is 15
*iptr is 15
rptr is 15
After changing i to 29:
i is 29
*iptr is 29
rptr is 29
 

 

(2) 引用的使用

(1)引用名可以是任何合法的变量名。除了用作函数的参数或返回类型外,在声明时,必须立即对它进行初始化,不能声明完后再赋值。

 


int i;
int &j;
j=i;
 

 

(2)引用不能重新赋值,不能再把该引用名作为其他变量名的别名,任何对该引用的赋值就是该引用对应的目标变量名的赋值。对引用求地址,就是对目标变量求地址。

 

int i=5;
int &j1=i; 
int &j2=j1; 


int num=50;
int & ref=num;
int *p=&ref;

 

 

(3)由于指针变量也是变量,所以,可以声明一个指针变量的引用。方法是: 类型标识符 *&引用名=指针变量名;

 


#include 
void main()
{
    int *a; //定义指针变量a
    int *&p=a; //定义引用p,初始化为指针变量a,所以p是a的引用(别名)
    int b=10;
    p=&b; //等价于a=&b,即将变量b的地址赋给a。
    cout<<*a<
 

 

(4)引用是对某一变量或目标对象的引用,它本身不是一种数据类型,因此引用本身不占存储单元,这样,就不能声明引用的引用,也不能定义引用的指针。

 


int a;
int & & ra=a; //错误
int &*p=&ra; //错误
 

 

(5)不能建立数组的引用,因为数组是一个由若干个元素所组成的集合,所以就无法建立一个数组的别名。

(6)不能建立空指针的引用

 


int &rp=NULL; //错误
 

 

(7)也不能建立空类型void的引用,因为尽管在C++语言中有void数据类型,但没有任何一个变量或常量属于void类型。

 


void &ra=3; //错误
 

 

(8) 尽管引用运算符与地址操作符使用相同的的符号,但时不一样的。引用仅在声明时带有引用运算符&,以后就像普通变量一样使用,不能再带&。其他场合使用的&都是地址操作符。

 


int j=5;
int& i=j; // 声明引用i, "&"为引用运算符
i=123; // 使用引用i,不带引用运算符
int *pi=&i; // 在此, "&"为地址操作符
cout<<π // 在此, "&"为地址操作符
 

 

(3) 用引用作为函数的参数

    一个函数的参数也可定义成引用的形式:


void swap(int &p1, int &p2) //形参p1, p2都是引用
{
    int p;
    p=p1;
    p1=p2;
    p2=p;
}
      在主调函数的调用点处,直接以变量作为实参进行调用即可,不需要实参变量有任何的特殊要求。

swap(a,b); //直接以a和b作为实参调用swap函数
 

 

    例1.17 采用指针参数的例子:

 


#include
void swap(int *m, int *n)
{
    int temp;
    temp=*m;
    *m= *n;
    *n=temp;
}
main()
{
    int a=5, b=10;
    cout<<"a="<>num1;
    cout<<"Enter the second number: ";
    cin>>num2;
    max(num1,num2)=0;
    cout<<"
After putting zero in largest, the numbers are";
    cout<<"
"<>num1;
    cout<<"Enter the second number:";
    cin>>num2;
    min(num1, num2)=0;
    cout<<"
After putting zero in smallest the numbers are";
    cout<<"
"<num2)?num1:num2;
}
int &min(int &num1,int &num2)
{
    return (num1
 

 

审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分