编写strcpy函数和类String的构造函数、析构函数、赋值函数和重载运算符函数

合集下载

(0166)《面向对象技术》复习思考题

(0166)《面向对象技术》复习思考题

(0166)《面向对象技术》复习思考题一、选择题1、以下说法中正确的是( )A.C++程序总是从第一个定义的函数开始执行B.C++程序总是从main函数开始执行C.C++函数必须有返回值,否则不能使用函数D.C++程序中有调用关系的所有函数必须放在同一个程序文件中2、一个函数功能不太复杂,但要求被频繁调用,选用()A.内联函数 B.重载函数C.递归函数 D.嵌套函数3、构造函数不具备的特征是 ( )A.构造函数的函数名与类名相同B.构造函数可以重载C.构造函数可以设置默认参数D.构造函数必须指定类型说明4、下列不是描述类的成员函数的是()A. 友元函数 B.析构函数C.构造函数 D.拷贝构造函数5、int Func(int,int);不可与下列哪个函数构成重载()A.int Func(int,int,int); B.double Func(int,int);C.double Func(double,double);D.double Func(int,double);6、一个类可包含析构函数的个数是()A.0个 B.1个C.至少一个D.0个或多个7、在编译指令中,宏定义使用哪个指令()A.#include B.#defineC.#if D.#else8、在关键字public后面定义的成员为类的( )A.私有成员B. 保护成员C. 公有成员D.任何成员9、下列关于指针的运算中,( )是非法的。

A.两个指针在一定条件下,可以进行相等或不等的运算;B.可以用一个空指针赋值给某个指针;C.一个指针可以加上两个整数之差;D.两个指针在一定条件下,可以相加。

10、在C++中,关于下列设置缺省参数值的描述中,正确的是( )。

A. 不允许设置缺省参数值;B. 在指定了缺省值的参数右边,不能出现没有指定缺省值的参数;C. 只能在函数的定义中指定参数的缺省值;D. 设置缺省参数值时,必须全部都设置。

11、预处理命令在程序中是以( )开头的。

创维笔试秘籍

创维笔试秘籍

创维笔试秘籍1.1 笔试概述创维集团的招聘笔试针对不同类型的岗位会有不同的题目。

例如技术类的岗位会考查相关专业知识的内容,而营销类的岗位则偏向考查思维能力、逻辑推理能力等内容。

1.2 笔试真题创维技术类面试笔试题一、填空1. 二极管有 1 个PN结,三极管有 2 个PN结。

2 流过电感元件两端的电流发生变化时,会在电感元件两端产生感应电压。

3 基本放大电路根据其信号输入输出的接法不同,有共射组态、共集组态度、共基组态三种组态之分,这三种组态是最基本的放大单元电路。

4 描述正弦交流信号U(s)=Asin(ωt+φ)的三种物理量A、ω、φ含义分别是、、5 正弦波震荡电路是由放大电路和选频网络组成的。

6 二进制数11010用十进制数表示为26 ;十进制数18用二进制数表示为10010二进制数1101+1001= 10110 (用二进制数表示)7 电容的国际单位为法拉力(中/英文), 3.3×104PF= UF= F8 理想化集成运算放大器的两个特性是、,该特性也是分析理想化运放电路的基本原则。

9 三极管从放大机理上来说是放大信号的(电流/电压?)10. 三极管的三种工作状态为、、.二、问答1.请简述调制的作用及方式,与调制相对应的方式是什么?2 .请画出二极管、三极管(PNP、NPN型各一个)、晶闸管的电路符号图。

分别说明各自的用途有哪些?3.分析说明下面的二极管检波电路的检波原理,说出二极管、电容、电阻的各自作用,画出U2的大致波形。

三、计算题(要求写出计算步骤,直接写结果不计分)1、如下图之电路,求电流I1和I2的大小(提示:根据基尔霍夫电流定律)要求:写出基尔霍夫求职胜经/简历亮出你的精彩简历写作技巧,...面试前准备才是...电流定律的基本内容.A2、下图中二极管为理想二极管(不考虑导通压降与内阻),计算,当电源电压分别为+10V 和-10V时流过R1的电流是多少?3.请计算下列的等值阻值或电容值.四翻译1、I go to school on foot everyday.2、I am looking for work,so I must study try my best everyday.创维营销笔试题它涉及的内容没有营销专业方面的题目,而是其他的。

含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数

含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数

含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数编译器⾃带拷贝构造(ctor)和拷贝赋值函数(operator =),但是对于成员变量含有指针的类,其不能使⽤默认的拷贝赋值函数。

因为使⽤默认的,会直接将指针指向的地址进⾏赋值 (浅拷贝,共享内存,共指⼀个对象),⽽不是分配⼀块内存,具有相同的数值 (深拷贝,独⽴,两个对象)。

浅拷贝容易造成dangling pointer。

⽤⼀个例⼦来展⽰:1 #ifndef __MYSTRING__2#define __MYSTRING__34class String{5public:6 String(const char* cstr=0);7 String(const String& str); // 拷贝构造8 String& operator= (const String& str); // 拷贝赋值9 ~String();10char* get_c_str const(){11return m_data;12 }13private:14char* m_data; // 带指针成员的类:⼀定要注意拷贝赋值,拷贝构造,析构15// String的底部通过char实现,在外部表现为string16 };1718 inline String::String ( const char* cstr=0 ){19if(cstr){20 m_data=new char[strlen(cstr)+1];21 strcpy(m_data,cstr); // char * strcpy ( char * destination, const char * source );22 }23else{ // 考虑cstr=0;24 m_data=new char[1];25 m_data[0]='\0';26 }27 }2829 inline String::String(const String& str){30 m_data=new char[strlen(str.get_c_str())+1];31 strcpy(m_data,str.m_data);32 }3334 inline String::~String(){35delete[] m_data;36 }3738 inline String& String::operator=(const String& str){39if(this==&str){ // self assignment :⾃我检验(如果没有进⾏这样的处理,在⾃我赋值会产⽣严重的错误)40return *this;41 }42// 构造函数是第⼀次,因此不需要删除,但是赋值需要先进⾏delete43delete[] m_data; // 先删除,重新分配⼀样⼤⼩!44 m_data=new char[strlen(str.get_c_str())+1];45 strcpy(m_data,str.m_data);46return *this; // 其实不⽤返回*this也可以,因为已经实现了修改,但是这样有⼀个好处可以实现 a=b=c;(因为返回的类型继续⽀持=)47 }4849// 调⽤形式: cout << String() ; 第⼀个参数为 << 左边,第⼆个参数为 << 右侧;返回ostream 可以实现 cout << a << b ;50 ostream& operator<<(ostream& os,const String& str){51 os<<str.get_c_str();52return os;53 }5455#endif。

2009年C++笔试试卷(A卷)答案&解析

2009年C++笔试试卷(A卷)答案&解析

湖南大学课程考试试卷考试中心填写:C. 使用作用域分辨操作符或虚基类D. 使用虚基类或赋值兼容规则10.如果在类CTest的外面函数调用CTest::f();则函数f()是类CTest的( A )。

A. 静态成员函数B. 非静态成员函数C. 友元函数D. 前面都不正确析:友元函数不输入类成员,故不能那样调用。

11.对虚基类的定义,( B )。

A. 不一定要使用虚函数B. 必须使用虚函数C. 必须使用privateD. 必须使用public12.假定CTest为一个类,并且构造函数的参数无缺省值,则执行CTest objTest语句时将自动调用该类的( A )。

A. 有参构造函数B. 无参构造函数C. 拷贝构造函数D. 赋值重载函数析:无缺省值既有默认值,例如A(int i=0,double=”hello”).13.当一个类的某个函数被说明为virtual时,该函数在该类的所有派生类中( A )。

A. 都是虚函数B. 只有被重新说明时才是虚函数C. 只有被重新说明为vittual时才是虚函数D. 都不是虚函数析:之后,派生类的该虚函数前的virtual关键字可加可不加14.调用一个成员函数时,使用动态联编的情况是( B )。

A. 通过对象调用一虚函数B. 通过指针或引用调用一虚函数C. 通过对象调用一静态函数D. 通过指针或引用调用一静态函数析:记住,通过对象调用虚函数不会出现多态(通过指针或者引用才会有多态性)在构造函数里面调用虚函数不会出现多态指定命名域调用不会出现多态15.在派生类中能够直接访问基类的( D )。

A. 公有成员和私有成员B. 保护成员和私有成员C. 不可访问的和私有的成员D. 保护成员和公有成员二、判断正误题(本大题共10小题,每小题1分,共10分)判断正误,在题后的括号内,正确的划上“√”错误的划上“×”。

1.friend属于类的存取权限。

(√)2.重载函数要求函数有相同的函数名,但具有不同的参数个数或参数类型。

详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现

详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现

详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现C++中⼀般创建对象,拷贝或赋值的⽅式有构造函数,拷贝构造函数,赋值函数这三种⽅法。

下⾯就详细⽐较下三者之间的区别以及它们的具体实现1.构造函数构造函数是⼀种特殊的类成员函数,是当创建⼀个类的对象时,它被调⽤来对类的数据成员进⾏初始化和分配内存。

(构造函数的命名必须和类名完全相同)⾸先说⼀下⼀个C++的空类,编译器会加⼊哪些默认的成员函数默认构造函数和拷贝构造函数析构函数赋值函数(赋值运算符)取值函数**即使程序没定义任何成员,编译器也会插⼊以上的函数!注意:构造函数可以被重载,可以多个,可以带参数;析构函数只有⼀个,不能被重载,不带参数⽽默认构造函数没有参数,它什么也不做。

当没有重载⽆参构造函数时,A a就是通过默认构造函数来创建⼀个对象下⾯代码为构造函数重载的实现<span style="font-size:14px;">class A{int m_i;Public:A(){Cout<<”⽆参构造函数”<<endl;}A(int i):m_i(i) {} //初始化列表}</span>2.拷贝构造函数拷贝构造函数是C++独有的,它是⼀种特殊的构造函数,⽤基于同⼀类的⼀个对象构造和初始化另⼀个对象。

当没有重载拷贝构造函数时,通过默认拷贝构造函数来创建⼀个对象A a;A b(a);A b=a; 都是拷贝构造函数来创建对象b强调:这⾥b对象是不存在的,是⽤a 对象来构造和初始化b的!!先说下什么时候拷贝构造函数会被调⽤:在C++中,3种对象需要复制,此时拷贝构造函数会被调⽤1. 1)⼀个对象以值传递的⽅式传⼊函数体2. 2)⼀个对象以值传递的⽅式从函数返回3. 3)⼀个对象需要通过另⼀个对象进⾏初始化什么时候编译器会⽣成默认的拷贝构造函数:1. 1)如果⽤户没有⾃定义拷贝构造函数,并且在代码中使⽤到了拷贝构造函数,编译器就会⽣成默认的拷贝构造函数。

c++ string类的常用方法

c++ string类的常用方法

c++ string类的常用方法一、C++ string类的常用方法1、string类的构造函数string() // 构造空串string(const char* s) // 把null结尾的字符串s拷贝到字符串中string(const string& str) // 拷贝构造函数,复制str到此串string(char c, int n) // 用n个字符c构造串string(const char* s, int n) // 拷贝字符数组中前n个字符2、string类的成员函数2.1 长度控制函数int size() const; // 返回字符串的长度int length() const; // 返回字符串的长度,等价于size()void resize(int n, char c); // 改变字符串长度,如果n 大于原来的长度,用字符c来填充2.2 内容操作函数string& operator=(const char* s); // 赋值,把s的内容复制到字符串中string& assign(const char* s); // 赋值,把s的内容复制到字符串中string& append(const char* s); // 把字符串s添加到串尾string& append(const char* s, int n); // 把s前n个字符添加到串尾string& insert(int p0, const char* s); // 在p0位置上插入字符串sstring& erase(int p0, int n); // 删除p0开始,n个字符int find(const char* s, int pos=0); // 在pos之后查找子串s,返回子串s在原串中的起始位置int find(char c, int pos=0); // 从pos开始查找字符c,返回字符c在原串中的位置int rfind(const char* substr,int pos=npos); // 从pos开始向前查找子串substr,返回子串substr在原串中的起始位置int rfind(char c, int pos=npos); // 从pos开始向前查找字符c,返回字符c在原串中的位置string substr(int pos, int n); // 返回串pos 位置开始,长度为n的子串2.3 字符串比较函数int compare(const char* s); // 比较原串和sint compare(int p0, int n, const char* s); // 比较串中p0开始,n个字符的子串和s2.4 数据访问函数char& operator[](int i); // 返回串中第i个字符的引用const char& operator[](int i) const; // 返回串中第i个字符的引用const char* c_str() const; // 返回字符串以null结尾的字符串2.5 输入输出函数ostream& operator<<(ostream& os, const string& str); // 输出字符串istream& operator>>(istream& is, string& str); // 输入字符串。

C++考试题和答案

C++考试题和答案

郑州轻工业学院 2009/2010学年 第1学期《C++》试题A1.下列运算符种,( )运算符在C++中不能重载。

A )>> B )[ ] C )? : D )&& 2.C++源程序文件的扩展名为( )。

A ).EXEB ).C C ).DLLD ).CPP3.下列关于动态联编的描述中,错误的是( )。

A )动态联编是以虚函数为基础的B )动态联编是在运行时确定所调用的函数代码的C )动态联编调用函数操作是指向对象的指针或对象引用D )动态联编是在编译时确定操作函数的4.下面的函数声明中, 哪一个是" void BC(int a, int b );"的重载函数( )。

A )int BC(int x, int y ); B )void BC(int a, char b );C )float BC(int a, int b, int c=0);D )int BC(int a, int b = 0);5.对类的构造函数和析构函数描述正确的是( )。

A )构造函数可以重载,析构函数不能重载 B )构造函数不能重载,析构函数可以重载 C )构造函数可以重载,析构函数也能重载 D )构造函数不能重载,析构函数也不能重载6.C++中类有两种用法:一种是类的实例化,即生成类的对象,并参与系统的运行;另一种是通过( )派生出的新类。

A )复用B )继承C ) 封装D )引用 7.在下面的4个选项中,( )是用来声明虚函数的。

A )virtual B )public C )using D )false 8.下面对于友元函数的描述是正确的是( )。

A )友元函数的实现必须在类的内部定义 B )友元函数是类的成员函数C )友元函数破坏了类的封装性和隐藏性D )友元函数不能是访问类的私有成员9.假定MyClass 为一个类,则该类的拷贝初始化构造函数的声明语句是( )。

C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容

C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容

C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执⾏顺序和执⾏内容⼀、本⽂⽬的与说明1. 本⽂⽬的:理清在各种继承时,构造函数、复制构造函数、赋值操作符、析构函数的执⾏顺序和执⾏内容。

2. 说明:虽然复制构造函数属于构造函数的⼀种,有共同的地⽅,但是也具有⼀定的特殊性,所以在总结它的性质时将它单独列出来了。

3. 单继承、多继承、虚继承,既然都属于继承,那么虽然有⼀定的区别,但还是相同点⽐较多。

如果放在⼀块讲,但为了将内容制作成递进的,就分开了,对相同点进⾏重复,(⼤量的复制粘贴哈),但在不同点进⾏了标注。

注意:三块内容是逐步递进的如果你懂虚函数,那么单继承和多继承那块你就可以不看;如果你懂多继承,那单继承你就不要看了,⾄于虚继承就等你懂虚继承再回来看吧;如果你只懂单继承,那你就只看单继承就好。

⼆、基本知识1. 对于⼀个空类,例如:class EmptyClass{};虽然你没有声明任何函数,但是编译器会⾃动为你提供上⾯这四个⽅法。

class EmptyClass {public:EmptyClass(); // 默认构造函数EmptyClass(const EmptyClass &rhs); // 复制构造函数~EmptyClass(); // 析构函数EmptyClass& operator=(const EmptyClass &rhs); // 赋值运算符}对于这四个⽅法的任何⼀个,你的类如果没有声明,那么编译器就会⾃动为你对应的提供⼀个默认的(注意合成默认构造函数是⽤于没有编写构造函数编译器才会合成默认构造函数,其中复制构造函数也是构造函数)。

(在《C++ primer》中,这个编译器⾃动提供的版本叫做“合成的***”,例如合成的复制构造函数)当然如果你显式声明了,编译器就不会再提供相应的⽅法。

2. 合成的默认构造函数执⾏内容:如果有⽗类,就先调⽤⽗类的默认构造函数。

C++笔试题目-带答案

C++笔试题目-带答案

姓名:___________ 时间:___________DCCBB AADAD一、选择题(1*10=10)1.如果派生类以proctected方式继承基类,则原基类的protected和public 成员在派生类的访问性分别是:DA.public和public B.public和protected C.protected和public D.protected和protected解析:通过protected方式继承基类后,原基类的私有成员不可访问,而protected和public成员均变成protected成员。

答案:D2.有如下头文件:int F1();static int F2();classs CA{public:int F3();static int F4();};在所描述的函数中,具有隐含this指针的是:CA.F1 B.F2C.F3 D.F4本题考查的是this指针。

this指针式一个隐含的指针,它隐含于每个类的非静态成员函数中,它明确地表示出了成员函数当前操作的数据所属的对象。

当对一个对象调用成员函数时,编译程序先将对象的地址赋值给this指针,然后调用成员函数,每次成员函数存取数据成员时,则隐含使用this指针。

this指针是指向对象本身的指针,它只存在于类的非静态成员中。

f1,f2不是成员函数,不存在隐含指针;f4为静态成员函数,也不含有this指针;含有this指针的函数在调用时按thiscall调用约定调用。

故本题答案为C。

3.派生类的成员函数不能访问基类的:CA.共有成员和保护成员B.共有成员C.私有成员D.保护成员本题考查的是继承的类型。

类的继承方式有公有继承、保护继承和私有继承三种方式。

对于公有继承基类中的成员访问属性不变,对于保护和私有继承基类中的成员转换为相应的访问类型。

但是如果基类成员的访问属性为private的,则不能被继承。

故本题答案为C。

4.按照“后进先出”原则组织数据的数据结构是BA.队列B.栈C.双向链表D.二叉树答案为B。

c++ string类的常用方法

c++ string类的常用方法

c++ string类的常用方法x1、string类的构造函数string类的构造函数有三种:(1)默认构造函数:string();(2)以字符串常量指针为参数的构造函数:string (const char *s);(3)以字符串对象为参数的构造函数:string (const string &str);2、string类的赋值操作string类的赋值操作有以下几种:(1)以字符串常量指针为参数的赋值运算符重载:string & operator = (const char *s);(2)以字符串对象为参数的赋值运算符重载:string & operator = (const string &str);(3)拼接函数:string &append (const string &str);(4)两个字符串的拼接:string + string;3、string类的比较操作string类的比较操作有如下几种:(1)比较两个字符串是否相等的比较操作符:string==string;(2)比较两个字符串是否不等的比较操作符:string!=string;(3)比较两个字符串大小的比较操作符:string>string;4、string类的查找操作string类的查找操作有以下几种:(1)查找从某个位置开始某个子串的位置的函数:size_tfind(const string &str,size_t pos = 0);(2)查找从某个位置开始某个字符的位置的函数:size_tfind(char c,size_t pos = 0);(3)查找从右向左某个子串的位置的函数:size_t rfind(const string &str,size_t pos = string::npos);(4)查找从右向左某个字符的位置的函数:size_t rfind(char c,size_t pos = string::npos);5、string类的修改操作string类的修改操作有以下几种:(1)插入字符串的函数:string &insert (size_t pos, const string &str);(2)替换某个子串的函数:string &replace (size_t pos, size_t len, const string &str);(3)删除某个子串的函数:string &erase (size_t pos = 0, size_t len = npos);(4)在字符串前面补充某字符的函数:string &insert (size_t pos, size_t n, char c);(5)清除字符串的函数:void clear();6、string类的截取操作string类的截取操作有以下几种:(1)从某个位置截取字符串的函数:string substr (size_t pos = 0, size_t n = npos);(2)将字符串按照一定的字符分割成多个小字符串的函数:vector<string> split(char c);(3)删除收尾处的某字符的函数:string &trim(char c);。

c string类的常用方法

c string类的常用方法

c string类的常用方法在C语言中,字符串通常表示为字符数组,而不是像C++那样有专门的字符串类。

但C标准库中提供了一些用于操作和处理字符串的函数。

以下是其中的一些常用方法:1. strcpy():将一个字符串复制到另一个字符串。

```cchar str1[50];strcpy(str1, "Hello, World!");```2. strcat():将一个字符串连接到另一个字符串的末尾。

```cchar str1[50] = "Hello, ";strcat(str1, "World!");```3. strlen():返回字符串的长度,不包括终止字符'\0'。

```cchar str[] = "Hello, World!";printf("%d", strlen(str)); // 输出 13```4. strcmp():比较两个字符串。

```cchar str1[] = "Hello";char str2[] = "World";if (strcmp(str1, str2) < 0) {printf("%s is less than %s\n", str1, str2);} else if (strcmp(str1, str2) > 0) {printf("%s is greater than %s\n", str1, str2); } else {printf("%s is equal to %s\n", str1, str2);}```5. strstr():在字符串中查找子串。

```cchar str[] = "Hello, World!";char sub[] = "World";char result = strstr(str, sub);if (result != NULL) {printf("Found '%s' in '%s'\n", sub, str);} else {printf("Did not find '%s' in '%s'\n", sub, str); }```6. sprintf():将格式化的数据写入字符串。

C++基础面真题

C++基础面真题

1.const符号常量:〔1〕、const char Xp〔2〕、char const Xp〔3〕、char X const p如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量。

如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

2.析构函数和虚函数的用法和作用?析构函数的作用是当对象生命期结束时释放对象所占用的资源。

析构函数用法:析构函数是特别的类成员函数它的名字和类名相同,没有返回值,没有参数不能随意调用也没有重载。

只是在类对象生命期结束时有系统自动调用。

虚函数用在继承中,当在派生类中需要重新定义基类的函数时需要在基类中将该函数声明为虚函数,作用为使程序支持动态联遍。

3.堆和栈的区别栈〔stack〕:由编译器自动分配释放,存放函数的参数值,局部变量的值等。

其操作方法类似于数据结构中的栈。

堆:一般由程序员分配释放,假设不释放,程序结束时可能由OS回收。

注意它与数据结构中的堆是两回事,分成分法类似。

4.头文件的作用是什么?1.通过头文件来调用库功能。

在很多场合,源代码不便〔或不准〕向用户公布,只要向用户提供头文件和二进制的库即可。

用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么完成的。

编译器会从库中提取出相应的代码。

2.头文件能加强类型平安检查。

如果某个接口被完成或被使用时,其方法与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。

5.内存的分成分法有几种?1.从静态存储地域分配。

内存在程序编译的时候已经分配好,这块内存在程序的整个运行期间都存在。

如全局变量。

2.在栈上创立。

在执行函数时,函数内局部变量的存储单元都可以在栈上创立,函数执行结束时这些存储单元自动被释放。

栈内存分配运算内置于处理器的指令集中,效率高,但是分配的内存容量有限。

3.从堆上分配,亦称动态内存分配。

程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。

[学习C++]构造函数 析构函数和赋值操作符

[学习C++]构造函数 析构函数和赋值操作符

几乎所有的类都有一个或多个构造函数,一个析构函数和一个赋值操作符。

这没什么奇怪的,因为它们提供的都是一些最基本的功能。

构造函数控制对象生成时的基本操作,并保证对象被初始化;析构函数摧毁一个对象并保证它被彻底清除;赋值操作符则给对象一个新的值。

在这些函数上出错就会给整个类带来无尽的负面影响,所以一定要保证其正确性。

本章我将指导如何用这些函数来搭建一个结构良好的类的主干。

构造函数,析构函数和赋值操作符几乎所有的类都有一个或多个构造函数,一个析构函数和一个赋值操作符。

这没什么奇怪的,因为它们提供的都是一些最基本的功能。

构造函数控制对象生成时的基本操作,并保证对象被初始化;析构函数摧毁一个对象并保证它被彻底清除;赋值操作符则给对象一个新的值。

在这些函数上出错就会给整个类带来无尽的负面影响,所以一定要保证其正确性。

本章我将指导如何用这些函数来搭建一个结构良好的类的主干。

条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符看下面一个表示string对象的类:// 一个很简单的string类class string {public:string(const char *value);~string();... // 没有拷贝构造函数和operator=private:char *data;};string::string(const char *value){if (value) {data = new char[strlen(value) + 1];strcpy(data, value);}else {data = new char[1];*data = '\0';}}inline string::~string() { delete [] data; }请注意这个类里没有声明赋值操作符和拷贝构造函数。

这会带来一些不良后果。

如果这样定义两个对象:string a("hello");string b("world");其结果就会如下所示:a: data——> "hello\0"b: data——> "world\0"对象a的内部是一个指向包含字符串"hello"的内存的指针,对象b的内部是一个指向包含字符串"world"的内存的指针。

c语言构造函数和析构函数

c语言构造函数和析构函数

c语言构造函数和析构函数C语言构造函数和析构函数构造函数和析构函数是面向对象编程(OOP)中的重要概念。

它们用于在对象的创建和销毁过程中执行特定的操作。

然而,在C语言中并没有内置的构造函数和析构函数的概念,因为C语言不直接支持面向对象编程。

然而,我们可以通过一些技巧来模拟构造函数和析构函数的行为。

本文将逐步解释如何实现这些概念,并探讨构造函数和析构函数在C语言中的应用。

第一步:模拟构造函数构造函数在对象创建时被自动调用,用于初始化对象的成员变量。

在C语言中,我们可以通过在函数中手动分配内存并初始化对象来模拟构造函数的行为。

首先,我们需要定义一个结构体来表示我们要创建的对象。

结构体可以包含多个成员变量,每个成员变量代表对象的一个属性。

例如,我们可以创建一个学生对象,其中包含姓名和年龄两个成员变量。

ctypedef struct {char name[20];int age;} Student;接下来,我们可以编写一个创建学生对象的函数,该函数将分配内存并初始化学生对象的成员变量。

cStudent* createStudent(char* name, int age) {Student* student = (Student*)malloc(sizeof(Student));strcpy(student->name, name);student->age = age;return student;}在上述代码中,我们使用malloc函数分配了一块内存,大小足够容纳一个Student结构体。

然后,我们使用strcpy函数将传入的姓名参数复制到student对象的name成员变量中,使用赋值运算符初始化age成员变量。

最后,我们将指向新创建的学生对象的指针返回。

现在,我们可以调用createStudent函数来创建一个学生对象,并访问其成员变量。

cint main() {Student* student = createStudent("Tom", 20);printf("Name: s, Age: d\n", student->name,student->age);free(student);return 0;}在上述代码中,我们首先调用createStudent函数来创建一个学生对象,并将返回的指针赋给student指针。

C++复习5大基础函数(析构函数、构造函数、内联函数、拷贝构造函数、友元函数)详解

C++复习5大基础函数(析构函数、构造函数、内联函数、拷贝构造函数、友元函数)详解

1、析构函数2、构造函数3、内联函数4、拷贝构造函数5、友元函数1、析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。

析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

2、构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。

构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回void。

构造函数可用于为某些成员变量设置初始值。

3、内联函数有时称作在线函数(inline)。

函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作。

所谓“内联函数”就是将很简单的函数“内嵌”到调用他的程序代码中,只样做的目的是为了节约下原本函数调用时的时空开销。

但必须注意的是:作为内联函数,函数体必须十分简单,不能含有循环、条件、选择等复杂的结构,否则就不能做为内联函数了。

事实上,即便你没有指定函数为内联函数,有的编译系统也会自动将很简单的函数作为内联函数处理;而对于复杂的函数,即便你指定他为内联函数,系统也不会理会的。

内联函数也有一定的局限性。

就是函数中的执行代码不能太多了,如果,内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。

这样,内联函数就和普通函数执行效率一样了。

4、拷贝构造函数拷贝构造函数,又称复制构造函数。

复制构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。

它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象.为什么需要拷贝构造函数?把参数传递给函数有三种方法,一种是传值,一种是传地址,一种是传引用。

传值与其他两种方式不同的地方在于当使用传值方式的时候,会在函数里面生成传递参数的一个副本,这个副本的内容是按位从原始参数那里复制过来的,两者的内容是相同的。

c++经典课后习题整理(1)

c++经典课后习题整理(1)

(1)设计一个Car类,他的数据成员要能描述一辆汽车的品牌、型号、出厂年份和价格,成员函数包括提供合适的途径来访问数据成员,在main()函数中定义类的对象并调用相应的成员函数#include<iostream>#include<string>using namespace std;class Car{private:s tring Pingpai;s tring Xinghao;i nt Year;i nt Price;public:void set(){cout<<"shu ru xiang guan xin xi"<<endl;cout<<"pingpai:";cin>>Pingpai;cout<<"xinghao:";cin>>Xinghao;cout<<"chuchangnianfen:";cin>>Year;cout<<"jiage:";cin>>Price;}void show(){cout<<"pingpai:"<<Pingpai<<endl;cout<<"xinghao:"<<Xinghao<<endl;cout<<"chuchangnianfen:"<<Year<<endl;cout<<"jiage:"<<Price<<endl;}};int main(){Car car;car.set ();car.show ();return 0;}(2)设计一个学生类Student,拥有的数据成员是学号、姓名、电话号码、所属院系,成员函数包括访问和修改这些属性,在main()中定义对象,并输出相关信息#include <iostream>#include <string>using namespace std;class Student //学号、姓名、电话号码、所属院系,成员函数包括访问和修改这些属性{private:string xuehao;string name;string tel;string department;public:Student(string x,string n,string t,string d){xuehao=x;name=n;tel=t;department=d;}void change(string x,string n,string t,string d)//修改属性{xuehao=x;name=n;tel=t;department=d;}void display(){cout<<"xuehao="<<xuehao<<endl;cout<<"name="<<name<<endl;cout<<"tel="<<tel<<endl;cout<<"department="<<department<<endl;}};int main(){string a,b,c,d;cin>>a;cin>>b;cin>>c;cin>>d;Student s(a,b,c,d);s.display();return 0;}(3)设计一个学生类,包含学生呢个姓名、成绩(char *name;double score),设计一个友元函数,比较学生成绩的高低,并求出下一组学生:{Stu("zhang"),78,Stu("wang",80),Stu("li",65),Stu("chen",50)}中的最高分和最低分……#include<iostream>#include<string>using namespace std;class student{private:char *name;double score;public:student(){}student(char *na,double sc){name=na;score=sc;}friend void order(student s[]);};void order(student s[]){student tmp;int i,j;for(j=0;j<3;j++)for(i=0;i<3-j;i++)if(s[i].score<s[i+1].score){tmp=s[i];s[i]=s[i+1];s[i+1]=tmp;}cout<<"分数由高到低排列:";for(i=0;i<4;i++)cout<<s[i].name<<" "<<s[i].score<<endl;cout<<"最高分:"<<s[0].name<<" "<<s[0].score<<endl;cout<<"最低分:"<<s[3].name<<" "<<s[3].score<<endl;}int main(){students[4]={student("zhang",78),student("wang",80),student("li",92),student("chen",50 )};order(s);}(4)编写程序,定义机动车类Vehicle,包括的数据成员有出厂日期和售价并定义成员函数可以设置这些数据成员,再定义print()然后定义car类,增加乘客数量,truck类增加载重吨数.......#include<iostream>#include<string>using namespace std;class Vehicle{private:int year,month,day;int price;public:Vehicle(){cout<<"please input date: ";cout<<"year"<<","<<"month"<<","<<"day"<<","<<endl;cin>>year;cin>>month;cin>>day;cout<<"please input price:";cin>>price;cout<<"Vehicle"<<endl;}virtual void print1(){cout<<"date:"<<year<<","<<month<<","<<day<<","<<endl;cout<<"price:"<<price<<endl;}};class Car:public Vehicle{public:int amount;Car(){cout<<"please input amount of passager: ";cin>>amount;cout<<"car"<<endl;}void print2(){print1();cout<<"amount:"<<amount<<endl;}};class Truck:public Vehicle{public:int ton;Truck(){cout<<"please input ton:";cin>>ton;cout<<"truck"<<endl;}void print3(){print1();cout<<"ton:"<<ton<<endl;}};int main(){Vehicle V1;V1.print1();Car C1;C1.print2();Truck T1;T1.print3();return 0;}(7-4)完整定义字符串类string,使用动态分配内存机制实现字符串存储,定义构造函数,析构函数,重载运算符“=”,"+",“+=”实现两个字符串的赋值,连接等功能。

【精品】(0166)《面向对象技术》复习思考题.doc

【精品】(0166)《面向对象技术》复习思考题.doc

(0166)《面向对象技术》复习思考题一、选择题1、以下说法中正确的是()A.C++程序总是从第一个定义的函数开始执行B.C++程序总是从main函数开始执行C.C++函数必须有返冋值,否则不能使用函数D.C++程序中有调用关系的所有函数必须放在同一个程序文件中2、一•个函数功能不太复杂,但要求被频繁调用,选用()A.内联函数B.重载函数C.递归函数D.嵌套函数3、构造函数不具备的特征是()A.构造函数的函数幺与类名相同B.构造函数可以重载C.构造函数可以设置默认参数D.构造函数必须指定类型说明4、下列不是描述类的成员函数的是()A.友元函数B.析构函数C.构造函数D.拷贝构造函数int Func(int, int, int);double Func(int, int);5、int Func (int, int):不可与下列哪个函数构成重载()double Func(double, double); D. double Func (int, double):6、一•个类可包含析构函数的个数是()A.0个B. 1个C.至少一个D. 0个或多个7、在编译指令中,宏定义使用哪个指令()A.tfincludeB. #defineC. #ifD. ftelse8、在关键字public后面定义的成员为类的()A.私有成员B.保护成员C.公有成员D.任何成员9、下列关于指针的运算中,()是非法的。

A.两个指针在一定条件下,可以进行相等或不等的运算;B.可以用一个空指针赋值给某个指针;C.一•个指针可以加上两个整数之差;D.两个指针在一定条件下,可以相加。

10、在C++中,关于下列设置缺省参数值的描述中,止确的是()。

A.不允许设置缺省参数值;B.在指定了缺省值的参数右边,不能出现没有指定缺省值的参数;C.只能在函数的定义中指定参数的缺省值;0.设置缺省参数值时,必须全部都设置。

11、预处理命令在程序中是以()开头的。

strcpy用法与重写

strcpy用法与重写

strcpy⽤法与重写C语⾔标准库函数原型声明:extern char *strcpy(char *dest,char *src);头⽂件:功能:把src所指由NULL结束的字符串复制到dest所指的数组中。

说明:src和dest所指内存区域不可以重叠且dest必须有⾜够的空间来容纳src的字符串。

返回指向dest的指针。

典型实现[cpp]1. /**********************2. * C语⾔标准库函数strcpy的⼀种典型的⼯业级的最简实现3. * 返回值:4. * 返回⽬标串的地址。

5. * 对于出现异常的情况ANSI-C99标准并未定义,故由实现者决定返回值,通常为NULL。

6. * 参数:7. * strDeatination8. * ⽬标串9. * strSource10. * 源串11. ***********************/12. char *strcpy(char *strDestination, const char *strSource)13. {14. assert(strDestination && strSource);15. char *strD=strDestination;16. while ((*strDestination++=*strSource++)!='/0');17. NULL;18. return strD;19. }出现频率最⾼的笔试题strcpy写法题⽬: 已知strcpy函数的原型是: char * strcpy(char * strDest,const char * strSrc); 1.不调⽤库函数,实现strcpy函数。

2.解释为什么要返回char *。

解说:1.strcpy的实现代码[cpp]1. char* strcpy(char* strDest,const char* strSrc)2. {3. if((strDest==NULL)||(strSrc==NULL))4. throw "Invalid argument(s)";5. char* strDestCopy=strDest;6. while((*strDest++=*strSrc++)!='/0');7. return strDestCopy;8. }错误的做法: [1] (A)不检查指针的有效性,说明答题者不注重代码的健壮性。

c++ string类型的各种函数

c++ string类型的各种函数

c++ string类型的各种函数C++中的string类型是标准库提供的一个字符串类,它有许多实用的函数和方法。

以下是一些常用的string类型函数:1.构造函数和析构函数:○默认构造函数:string(),创建一个空字符串。

○拷贝构造函数:string(const string &str),创建一个与str 相同的字符串。

○字符串字面值构造函数:string("string_literal"),创建一个字符串字面值的副本。

○初始化列表构造函数:string(char c, int n),创建一个包含n个字符c的字符串。

2.字符串操作函数:○+:字符串连接操作,string s1 + s2。

○+=:字符串连接赋值操作,s1 += s2。

○[]:字符串切片操作,string s[begin, end)。

○at:字符串切片操作,string s.at(n)。

○find:查找子字符串在字符串中的位置,size_t find(const string &substr)。

○rfind:从字符串末尾开始查找子字符串的位置,size_t rfind(const string &substr)。

○substr:提取字符串的一部分,string substr(size_t pos, size_t len)。

○insert:在指定位置插入字符或子字符串,void insert(size_t pos, char c)或void insert(size_t pos, const string &substr)。

○erase:删除字符串中的字符或子字符串,void erase(size_t pos, size_t len)。

○replace:替换字符串中的子字符串,void replace(size_t pos, size_t len, const string &substr)。

c++第二阶段考试--答案

c++第二阶段考试--答案

C++第二阶段考试考试时间: 90分钟一、选择题(3分*10=30分)1.在结构化程序设计中,模块划分的原则是( )A. 各模块应包括尽量多的功能B. 各模块的规模应尽量大C. 各模块之间的联系应尽量紧密D. 模块内高内聚度,模块间低耦合度2.下面选项中不属于面向对象程序设计特征的是( )。

A.继承性B.多态性C.重载性D.封装性注:重载函数的定义:在相同的声明域中的函数名相同的,而参数表不同的,即通过函数的参数表而唯一标识并且来区分函数的一种特殊的函数。

编译器判断重载函数的第一步是确定该调用中所考虑的重载函数的集合,该函数集合被称为候选函数(candidant function)。

所谓候选函数就是与被调用函数同名的函数。

编译器判断重载函数的第二步分为两动作。

第一个动作是编译器从第一步选出的候选函数中调出可行函数(viable function)。

可行函数的函数参数个数与调用的函数参数个数相同(如S ( int )),或者可行函数的参数可以多一些,但是多出来的函数参数都要有相关的缺省值(如 S (double , double =1.2 );)第二个动作是根据参数类型的转换规则将被调用的函数实参转换(conversion)成候选函数的实参。

这里本着充分利用参数类型转换的原则,换句话说,尽可能的使用上参数类型转换。

当然转换要以候选函数为转换的目标。

编译器判断重载函数的第三步是从第二步中选出的可行函数中选出最佳可行函数(best matchsituation)。

在最佳可行函数的选择中,从函数实参类型到相应可行函数参数所用的转化都要划分等级,根据等级的划分(ranked),最后选出最佳可行函数3.为了取代C中带参数的宏,在C++中使用( )A. 重载函数B.内联函数C.递归函数D.友元函数注:优点1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编写strcpy函数和类String的构造函数、析构函数、赋值函数和重载运算符函数已知strcpy函数的原型是char *strcpy(char *strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。

(1)不调用C++/C的字符串库函数,请编写函数strcpychar *strcpy(char *strDest, const char *strSrc); //将源字符串加const,表明其为输入参数{assert((strDest!=NULL) && (strSrc !=NULL)); // 2分 //对源地址和目的地址加非0断言char *address = strDest; // 2分//为了实现链式操作,将目的地址返回while( (*strDest++ = * strSrc++) != …\0‟ ) // 2分NULL ;return address ; // 2分}(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?答:为了实现链式表达式。

// 2分例如int length = strlen( strcpy( strDest, “hello world”) );二、网上广泛流传的,也是摘自林锐的http://www.blog.sh/user3/skyflowing/archives/2006/60452.html题目:已知strcpy函数的原型是:char * strcpy(char * strDest,const char * strSrc);1.不调用库函数,实现strcpy函数。

2.解释为什么要返回char *。

解说:1.strcpy的实现代码char * strcpy(char * strDest,const char * strSrc){if ((strDest==NULL)||(strsrc="/=NULL"))//[1](我感觉应为&&)throw "Invalid argument(s)";//[2]char * strDestCopy=strDest;//[3]while ((*strDest++=*strSrc++)!='\0');//[4]return strDestCopy;}错误的做法:[1](A)不检查指针的有效性,说明答题者不注重代码的健壮性。

(B)检查指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。

在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。

所以C++专门增加了bool、true、false三个关键字以提供更安全的条件表达式。

(C)检查指针的有效性时使用((strDest==0)||(strsrc="/=0")),说明答题者不知道使用常量的好处。

直接使用字面常量(如本例中的0)会减少程序的可维护性。

0虽然简单,但程序中可能出现很多处对指针的检查,万一出现笔误,编译器不能发现,生成的程序内含逻辑错误,很难排除。

而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。

[2](A)return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。

从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。

(B)return 0;,说明答题者没有掌握异常机制。

调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。

妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。

应该以抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。

[3](A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。

[4](A)循环写成while (*strDest++=*strSrc++);,同[1](B)。

(B)循环写成while (*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。

循环体结束后,strDest字符串的末尾没有正确地加上'\0'。

2.返回strDest的原始值使函数能够支持链式表达式,增加了函数的“附加值”。

同样功能的函数,如果能合理地提高的可用性,自然就更加理想。

链式表达式的形式如:int iLength=strlen(strcpy(strA,strB));又如:char * strA=strcpy(new char[10],strB);返回strSrc的原始值是错误的。

其一,源字符串肯定是已知的,返回它没有意义。

其二,不能支持形如第二例的表达式。

其三,为了保护源字符串,形参用const限定strSrc所指的内容,把const char *作为char *返回,类型不符,编译报错。

类似的我们可以写出一个10分的strlen函数int strlen( const char *str ) //输入参数const{assert( strt != NULL ); //断言字符串地址非0int len;while( (*str++) != '\0' ){len++;}return len;}include <cstring>#include <iostream>using namespace std;//已知类String的原型为:class String{public:String(const char *str = NULL); // 普通构造函数String(const String &o ther); // 拷贝构造函数~ String(void); // 析构函数String& operato r =(const String &other); // 赋值函数String& operato r +(const String &other); //重载运算符+String& operato r -(const String &other); //重载运算符-bool operator==(const String &o ther); //重载"==",判断两个字符串相等bool operator<(const String &o ther);bool operator>(const String &o ther);friend ostream& operato r << (ostream &, const String &); //重载<<,这里必须使用friend,因为涉及到两个类之间私有成员的访问private:char *m_data; // 用于保存字符串};//请编写String的上述4个函数。

//普通构造函数String::String(const char *str){if(NULL==str){m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志'\0'的//加分点:对m_data加NULL 判断if(m_data!=NULL)*m_data = '\0';}else{int length = strlen(str);m_data = new char[length+1]; // 若能加NULL 判断则更好if(m_data!=NULL)strcpy(m_data, str);}}// String的析构函数String::~String(void){delete [] m_data; // 或delete m_data;}//拷贝构造函数String::String(const String &o ther) // 得分点:输入参数为const型{int length = strlen(other.m_data);m_data = new char[length+1]; //加分点:对m_data加NULL 判断if(m_data!=NULL)strcpy(m_data, o ther.m_data);}//赋值函数String& String::operato r=(const String &other) // 得分点:输入参数为const型{if(this == &other) //得分点:检查自赋值return *this;delete [] m_data; //得分点:释放原有的内存资源int length = strlen( other.m_data );m_data = new char[length+1]; //加分点:对m_data加NULL 判断if(m_data!=NULL)strcpy( m_data, o ther.m_data );return *this; //得分点:返回本对象的引用}String& String::operato r+(const String &other) //重载运算符+ {char temp[200];strcpy(temp,m_data);delete [] m_data;int length=strlen(this->m_data)+strlen(other.m_data);m_data=new char[length+1];if(m_data!=NULL)strcpy(m_data,temp);strcat(m_data,o ther.m_data);return *this;}String& String::operato r-(const String &other){char *temp,*p;if( (temp=strstr(m_data,other.m_data)) ==NULL){cout<<"没有符合的子串,不能使用'-'操作"<<endl;return *this;}else{p=temp;temp=temp+strlen(other.m_data);*p='\0';strcat(m_data,temp);}return *this;}//重载运算符"<<"ostream& operator<<(ostream &output, const String &other){output<<other.m_data;return output;}bool String::operator<(const String &o ther){if(strcmp(m_data,other.m_data)<0)return true;return false;}bool String::operator>(const String &o ther) {if(strcmp(m_data,other.m_data)>0)return true;return false;}bool String::operator==(const String &other) {if(strcmp(m_data,other.m_data)==0)return true;return false;}void main(){String s1("Hello,");String s2("World!");String s3(s2);//调用拷贝构造函数String s4(s2);String s5("Hello,World");String s6("Hello,World!");String s7("Hello,World!");String s8("o,W");String s9;//String s3;//调用构造函数中的默认构造.//s3=s2;// 调用重载后的赋值函数cout<<s1<<endl;cout<<s2<<endl;cout<<s3<<endl;s3=s1+s2;cout<<s1<<endl;cout<<s2<<endl;cout<<s3<<endl;if(s4==s2)cout<<"两个字符串相等"<<endl;elsecout<<"两个字符串不相等"<<endl;if(s5<s6)cout<<"s5小于s6"<<endl;else if(s5>s6)cout<<"s5大于s6"<<endl;elsecout<<"s5等于s6"<<endl;s9=s7-s8;cout<<s9<<endl;system("pause");}原文:/rgaofei/blog/item/f538fc081b332333b0351dd0.html。

相关文档
最新文档