第13章 类的构造、析构与赋值函数

合集下载

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

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

含有指针变量的类需要重写拷贝构造函数,拷贝赋值函数,析构函数编译器⾃带拷贝构造(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++_构造函数与析构函数

C++_构造函数与析构函数

C++_构造函数与析构函数构造函数与析构函数1 构造函数1.1 构造函数具有⼀些特殊的性质1.2 定义构造函数的⼀般形式1.3 利⽤构造函数创建对象2 成员初始化表3 缺省参数的构造函数4 重载构造函数5 拷贝构造函数5.1 ⾃定义拷贝构造函数5.2 缺省的拷贝构造函数5.3 调⽤拷贝构造函数的三种情况5.4 浅拷贝和深拷贝6 析构函数7 调⽤构造函数和析构函数的顺序8 对象的⽣存期构造函数和析构函数都是类的成员函数,但它们都是特殊的成员函数,执⾏特殊的功能,不⽤调⽤便⾃动执⾏,⽽且这些函数的名字与类的名字有关。

C++语⾔中有⼀些成员函数性质是特殊的,这些成员函数负责对象的建⽴、删除。

这些函数的特殊性在于可以由编译器⾃动地隐含调⽤,其中⼀些函数调⽤格式采⽤运算符函数重载的语法。

C++引进⼀个⾃动完成对象初始化过程的机制,这就是类的构造函数。

对象的初始化1. 数据成员是不能在声明类时初始化2. 类型对象的初始化⽅法:1. 调⽤对外接⼝(public成员函数)实现:声明类→定义对象→调⽤接⼝给成员赋值2. 应⽤构造函数(constructor)实现:声明类→定义对象→同时给成员赋值1. 构造函数构造函数是⼀种特殊的成员函数,它主要⽤于为对象分配空间,进⾏初始化。

1.1 构造函数具有⼀些特殊的性质:(1) 构造函数的名字必须与类名相同。

(2) 构造函数可以有任意类型的参数,但不能指定返回类型。

它有隐含的返回值,该值由系统内部使⽤。

(3) 构造函数是特殊的成员函数,函数体可写在类体内,也可写在类体外。

(4) 构造函数可以重载,即⼀个类中可以定义多个参数个数或参数类型不同的构造函数。

构造函数是不能继承(5) 构造函数被声明为公有函数,但它不能像其他成员函数那样被显式地调⽤,它是在定义对象的同时被调⽤的。

(6) 在声明类时如果没有定义类的构造函数,编译系统就会在编译时⾃动⽣成⼀个默认形式的构造函数,(7) 默认构造函数是构造对象时不提供参数的构造函数。

第13章 对象与类

第13章  对象与类

1-20
【题目192】创建一个employee类,该类中有字符数组, 表示姓名、街道地址、市、省和邮政编码。把表示构造 函数、changname()、display()的函数的原型放在类定 义中,构造函数初始化每个成员,display()函数把完整 的对象数据打印出来。其中的数据成员是保护的,函数 是公共的。 【分析】该试题主要考查类的定义。其中在类中定义了保护 类型的数据成员,在类中声明了公共类型的函数,而将 函数的具体定义放在了类外。在类外定义函数时,需要 在前面加上类名::表示函数的归属。
1-22
【题目197】定义计数器类Counter。要求具有以下成员: 计数器值;可进行增值和减值记数;可提供记数值。
【题目198】编写一个程序,采用一个类求n!,并输出10!的 值。 【题目199】编写一个程序,设计一个Cdate类,它应该满 足下面的条件: (1)用这样的格式输出日期:日-月-年; (2)输出在当前日期上加两天后的日期; (3)设置日期。
1-13
习题
【题目185】对于对象和类的关系,说法不正确的是? A.同属于一类的对象,具有相同的数据成员和成员函数 B.对象是具体的,是类的对象,同其他变量一样,先定义 后使用 C.同一类的不同对象,其具有的操作可不同 D.不同类的对象,可有相同的操作 【分析】该试题主要考查对象和类的关系。对于如上4个选 项而言,源自于同一个类的对象必然具有相同的数据成 员和成员函数,而不同类的对象可以有相同操作,但同 一类的不同对象具有的操作也应是相同的。因此,选项C 是错误的。此外,对象是类的具体化,而类是对象的抽 象化,对象在使用前必须先定义或先创建。



1-5
类的声明

• • • • • • •

构造函数和析构函数总论

构造函数和析构函数总论

对于相同域中的对象:先构造的后析构,后构造的先 析构。
静态(static)类成员
一、静态数据成员 1、定义: class CTest { public ; static int count ; ┆ }; CTest rect1,rect2,… //定义多个对象 注: 无论生成多少个CTest对象,只有一个count,因此它是由 所有CTest对象共有的。静态数据成员只存储一处,供所有 对象共用。静态数据成员能够实现多个对象的数据共享。
构造函数和析构函数总论
在类中可以定义两个指定功能成员函数: 构造函数 析构函数 一、 构造函数 用来生成对象,可以初始化对象的数据成 员,构造函数在有对象生成时有系统自动调用。
class crectangle { private : int left ; int right ; public : crectangle( int L, int R) //构造函数 {left=L; right=R ;} void getcoord ( int *L , int *R ) {*L=left ; *R = right } };
const对象和const成员函数
①对象定义中加入const,表示该对象为常对象, 常对象中的数据成员为常变量,不能改变该类 中任何数据成员的值,数据成员必须有初值。 常对象用来保护对象中的数据不被修改; ②类中的函数定义中加入const,表示该函数为 常成员函数,只能引用本类中的数据成员,而 不能不能改变它们。常对象只允许调用常函数。 ③类中的数据成员定义中加入const,表示该数据 成员为常数据成员,其值是不能改变的,只能 通过构造函数的成员初始化表对其进行初始化。
二.析构函数
1 、析构函数:用来释放对象,在对象 删除前,用它来做一些清理工作,它在 类对象销毁时自动调用。

构造函数与析构函数

构造函数与析构函数
构造函数与析构函数
1
回想一下变量和函数参数的初始化 变量 定义与赋值结合起来: int number=9902; 函数 应用缺省参数: void add(int a=0, int b=0); 目的 便于编程、保证变量的值不会无意义,减小 程序出错的可能性。 构造函数和析构函数是类中的特殊的成员函数,构 造函数, 创建并初始化类的数据成员。析构函数 , 对象撤消时的清理工作,削除对象,释放内存。
14
// employee的类外定义 employee :: employee () : x (215) // 初始化表 { … } // show()的定义。 void employee :: show() { cout << "\n x的值是:"<< x << endl; } // 主函数 void main() { //生成对象并为x赋予初始值 employee obj; //调用show显示x的值 obj.show(); }
8
//Exanple:为类 Person增加构造函数 #include <string.h> class Person { private: char m_strName[20]; int m_nAge; int m_nSex; public: Person(const char *name,int age,char sex) { strcpy(m_strName,name); m_nAge=age; m_nSex=(sex=='m'?0:1); } void Register(char *Name,int Age,char Sex); void GetName(char *Name); int GetAge(); char GetSex();};

C语言里面构造函数和析构函数的运用办法

C语言里面构造函数和析构函数的运用办法

C语言里面构造函数和析构函数的运用办法C语言里面构造函数和析构函数的运用办法摘要:构造函数与析构函数是一个类中看似较为简单的两类函数,但在实际运用过程中总会出现一些意想不到的运行错误。

本文将较系统的介绍构造函数与析构函数的原理及在C#中的运用,以及在使用过程中需要注意的若干事项。

关键字:构造函数;析构函数;垃圾回收器;非托管资源;托管资源一.构造函数与析构函数的原理作为比C更先进的语言,C#提供了更好的机制来增强程序的安全性。

C#编译器具有严格的类型安全检查功能,它几乎能找出程序中所有的语法问题,这的确帮了程序员的大忙。

但是程序通过了编译检查并不表示错误已经不存在了,在“错误”的大家庭里,“语法错误”的地位只能算是冰山一角。

级别高的错误通常隐藏得很深,不容易发现。

根据经验,不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成的,而初始化和清除工作很容易被人遗忘。

微软利用面向对象的概念在设计C#语言时充分考虑了这个问题并很好地予以解决:把对象的初始化工作放在构造函数中,把清除工作放在析构函数中。

当对象被创建时,构造函数被自动执行。

当对象消亡时,析构函数被自动执行。

这样就不用担心忘记对象的初始化和清除工作。

二.构造函数在C#中的运用构造函数的名字不能随便起,必须让编译器认得出才可以被自动执行。

它的命名方法既简单又合理:让构造函数与类同名。

除了名字外,构造函数的另一个特别之处是没有返回值类型,这与返回值类型为void的函数不同。

如果它有返回值类型,那么编译器将不知所措。

在你可以访问一个类的方法、属性或任何其它东西之前,第一条执行的语句是包含有相应类的构造函数。

甚至你自己不写一个构造函数,也会有一个缺省构造函数提供给你。

class TestClass{public TestClass(): base() {} // 由CLR提供}下面列举了几种类型的构造函数1)缺省构造函数class TestClass{public TestClass(): base() {}}上面已介绍,它由系统(CLR)提供。

东软培训考核试题答案(内部资料)

东软培训考核试题答案(内部资料)

东软培训考核试题答案(内部资料)⼀、单选题(共20分,每题1分)1、快速排序的时间复杂度_____。

A)B) O(n*n); C)O(n*n/2); ; D)O(log(n));2、计算程序执⾏完的结果:short a;char *p;a = 1234;p= (char *)&a*p = 56;请问题变量a的数值为______。

A)1234; B) 3456; C)5634;3、判断程序的结果:char * p = “Hello World”;*p = “A”;程序执⾏后的结果_______。

A) p指向的字符串为“Aello World”;“H ello World”;C)D) 结果未知;4、请问这个结构体所占的空间⼤⼩是______。

Typedef {Int a;Char b,Short c,Short d,}AA_t;A)16byte; B) 9 byte; D)85、有下列程序段char a[3],b[]=”China”;a = b;printf(“%s”,a);则______。

A)运⾏后将输出China Ch;C)运⾏后将输出Chi6、若有语句int * point,a =4 ;和point = &a______。

7 、语句int (*ptr)();的含义是______。

A)ptr是指向⼀维数组的指针变量;D)ptr是⼀个函数名,该函数的返回值是指向int类型的指针;8、若有以下定义和语句:struct student{int age;int num;};struct student stu[3] = {{1001,20},{1002,19},{1003,21}};main(){struct student *p;p = stu;...}则以下不正确的引⽤是______。

A)(p++)->num; B)p++; C)(*p).num;9、请正确指出下列指针的最确切的含义,int (*ptr)[3]、int *(*ptr)[4]、void* (*ptr)(void*)______。

构造函数和析构函数的作用

构造函数和析构函数的作用

构造函数和析构函数的作用构造函数是一种特殊的成员函数,它没有返回类型,与类名相同,并且在创建对象时自动调用。

构造函数用于初始化对象的成员变量或执行一些必要的操作,确保对象的有效状态。

构造函数的主要作用如下:1.初始化成员变量构造函数用于初始化对象的成员变量。

可以通过构造函数对成员变量进行赋值操作,设置对象的初始状态。

在构造函数中可以使用this指针来访问对象的成员变量,通过this指针可以明确地指出当前对象。

2.为对象分配内存空间构造函数还负责为对象分配内存空间。

在创建对象时,构造函数会根据类的定义动态分配内存空间,保证对象的有效性,避免对象的成员变量冲突或访问越界等问题。

3.执行必要的操作构造函数还可以执行一些必要的操作,如连接数据库、初始化指针、打开文件等。

这些操作可以确保对象在创建时处于正确的状态,便于后续的使用。

4.支持函数重载构造函数支持函数重载,即在同一个类中可以定义多个构造函数,根据参数的不同进行区分。

这样可以方便地根据需要创建不同类型或不同初始状态的对象。

5.构造函数链在一些情况下,可以通过构造函数链来避免重复的代码。

构造函数链是指一个构造函数调用另一个构造函数来完成一部分初始化工作。

通过构造函数链,可以简化代码,并确保对象被正确初始化。

总之,构造函数的主要作用是为对象分配内存空间、初始化成员变量、执行必要的操作,确保对象的有效状态。

析构函数是与构造函数对应的一种特殊成员函数,用于清理对象内的资源并进行析构操作。

析构函数在对象销毁时自动调用,与构造函数相反。

析构函数的主要作用如下:1.释放动态分配的内存空间析构函数负责释放动态分配的内存空间,确保对象销毁时资源能够被正确释放。

如果在构造函数中动态分配了内存,应该在析构函数中释放,避免内存泄漏。

2.断开与外部资源的连接析构函数还可以断开与外部资源的连接,如关闭数据库连接、关闭文件等。

这样可以避免资源的浪费和异常。

3.执行必要的清理操作析构函数还可以执行一些必要的清理操作,如释放锁、关闭线程等。

C#类的构造函数与析构函数

C#类的构造函数与析构函数

C#类的构造函数与析构函数1.构造函数:类的构造函数是用来创建类的一个实例。

创建一个实例的一般形式:类名实例名= new 类名(构造函数参数列表);构造函数和类中其他函数相比,是较为特殊的,它的名称必须和类同名。

定义一个构造函数的一般形式是:Class 类名{类名(参数表);//就是定义构造函数{//语句}}例子:using System;class MyClass{MyClass(){Console.WriteLine("启动构造函数");Console.ReadLine();}public static void Main(){MyClass cM = new MyClass();}}运行结果:MyClass()就是一个构造函数,构造函数是没有任何返回值的。

构造函数也可以携带参数,看下面的例子:using System;class userName{string Uname;//定义一个带参数的构造函数public userName(string name){Console.WriteLine("新建一个用户:");Uname = name;}public void ShowName(){Console.WriteLine("用户名是:"+ Uname); }public static void Main(){//用带参数的构造函数创建类的一个实例userName uN1 = new userName("zhanghua"); uN1.ShowName();Console.ReadLine();}}运行结果:2.析构函数定义一个析构函数的一般形式是:Class 类名{~类名(参数表);//定义析构函数{//语句}}析构函数的使用:using System;class First{public First(){Console.WriteLine("First's constructor is called");}~First(){Console.WriteLine("First's destructor is called");}}class Second{public Second(){Console.WriteLine("Sencond's constructor is called");}~Second(){Console.WriteLine("Second's destructor is called");}}class Third{public Third(){Console.WriteLine("Third's constructor is called");}~Third(){Console.WriteLine("Third's destructor is called");}}public class MainClass{public static void Main(){First myObject1 = new First();Second myObject2 = new Second();Third myObject3 = new Third();}}运行结果:。

[学习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"的内存的指针。

类、构造函数、析构函数

类、构造函数、析构函数

类:1、在类体中不允许对所定义的数据成员进行初始化。

2、类的成员函数描述类所表达的问题的行为。

类中所有的成员函数都必须在类体内进行说明。

但成员函数的定义既可以在类体内给出,也可以在类体外给出。

第一种方式是将成员函数直接定义在类的内部。

第二种方式是在类声明中给出对成员函数的说明,而在类外部对成员函数进行定义(但成员函数仍然在类范围内)。

这种在类外部定义的成员函数的一般格式是:<返回类型><类名>::<成员函数名>(<参数表>){<函数体>}在类体外定义成员函数时,要注意必须在成员函数名前加上类名和作用域运算符(::)。

作用域运算符用来标识某个成员属于某个类。

作用域运算符的使用格式如下:<类名>::<成员函数名>(<参数表>)或<类名>::<数据成员名>成员函数的两种定义方式之间是有差别的。

如果一个成员函数的声明和定义都在类体内,那么这个成员函数就是内联函数。

如果一个成员函数的声明在类体内,而定义在类体外,这时对该成员函数的调用是按一般函数进行的。

如果要将定义在类体外的成员函数也作为内联函数处理,就必须在成员函数的定义前加上关键字“inline”,以此显式地说明该成员函数也是一个内联函数。

成员函数除了可以定义为内联函数以外,也可以进行重载,可以对其参数设置默认值。

6.3 构造函数和析构函数1、构造函数和析构函数的定义。

构造函数的作用是在对象被创建时利用特定的值构造对象,将对象初始化为一种特定的状态,使该对象具有区别于其他对象的特征。

构造函数在对象被创建的时候由系统自动调用。

构造函数也是类的成员函数,但它是一种特殊的成员函数,它除了具有一般成员函数的特性之外,还具有一些特殊的性质:(1)构造函数的名字必须与类名相同;(2)构造函数不指定返回类型,它隐含有返回值,由系统内部使用;(3)构造函数可以有一个或多个参数,因此构造函数可以重载;(4)在创建对象时,系统会自动调用构造函数。

2、缺省构造函数和缺省析构函数缺省构造函数就是调用时不必提供参数的构造函数。

构造函数和析构函数和复制构造函数

构造函数和析构函数和复制构造函数

实验五【实验内容】构造函数和析构函数和复制构造函数构造函数1. 构造函数是类的一个特殊成员函数,它的函数名与类名相同。

2. 构造函数定义了对象数据成员的初始化方法,它只在创建对象时被系统自动调用,并且只在创建对象时调用一次,是为创建的对象分配内存空间和对数据成员进行初始化。

3. 构造函数无函数类型,没有返回值,一般都声明为公有函数。

4.C++规定,每个类必须有构造函数,没有构造函数就不能创建对象。

5.如果程序中未声明构造函数,则系统自动产生出一个默认形式的构造函数,如果提供了一个构造函数,系统就不能自动提供一个默认的构造函数。

6.构造函数可以重载,即可以定义多个参数及参数类型不同的构造函数。

复制构造函数又称拷贝构造函数,是一种特殊的构造函数,其形参为本类的对象引用。

功能是把初始值对象的每个数据成员的值都复制到新建立的对象。

如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个拷贝构造函数。

1. 当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现拷贝赋值。

2. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。

3. 当函数的返回值是类对象时,系统自动调用拷贝构造函数。

析构函数析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载,只有在类的生命周期结束的时候,由系统自动调用。

析构函数和构造函数的最主要的区别:调用期不同、构造函数可以有参数可以重载。

实验1设计一个学生类stu,其中含有数据成员name、english和math,分别表示学生的姓名、英语成绩与数学成绩,使用类的成员函数output 和total输出学生的基本信息和总成绩,并完成在main函数中的相应调用。

#include <iostream>using namespace std;class stu{public:stu(char n[]="",double e=0.0,double m=0.0);~stu();void input();void output();void total();private:char name[8];double english,math;};stu::stu(char n[],double e,double m){strcpy(name,n);english=e;math=m;}stu::~stu(){}void stu::input(){cout<<"请输入学生的姓名、英语成绩与数学成绩:"<<endl;cin>>name>>english>>math;}void stu::output (){cout<<"学生的姓名、英语成绩与数学成绩:"<<name<<","<<english<<","<<math<<endl;}void stu::total (){cout<<"学生的总成绩是:"<<english+math<<endl;}void main(){stu s1("张思宁",95,80),s2;s2.input ();s1.output ();s1.total ();s2.output() ;s2.total ();}实验2练习书上112页例4-2,熟悉复制构造函数被调用的3种情况。

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指针。

《高级语言程序设计》课程教学大纲

《高级语言程序设计》课程教学大纲

《高级语言程序设计》课程教学大纲56学时 3.5学分一、课程的性质、目的及任务《高级语言程序设计》是计算机科学与技术、电子信息科学与技术和信息安全专业的一门专业基础课,目的是主要培养运用C++语言进行程序设计的能力。

本课程一方面讲述C++语言的基本特性,包括指针、数组、函数、类、对象、派生类、继承、流类库等内容,另一方面系统地介绍面向对象程序设计的基本概念、分析方法、设计方法和编程方法。

具体的教学任务为:1.准确描述问题、分析问题,以及运用计算思维解决问题的能力。

2.正确理解和使用C++语言的基本数据结构和语法,掌握面向对象程序设计的基本思想和方法,进行正确、完善的程序设计的能力。

3.使用C++语言集成开发环境完成面向对象程序的编写、调试的任务。

二、适用专业计算机科学与技术专业、电子科学与技术专业、信息安全专业三、先修课程信息技术概论四、课程的基本要求掌握选择、循环等c++的基本语句;掌握数组、指针等数据类型;掌握函数、对象、文件等程序的组成成分;掌握面向对象程序设计的基本思想,能独立分析问题并编程实现;掌握Visual c++ 6.0程序设计环境的基本用法,能进行程序的编写、调试和运行。

五、课程的教学内容第1章C++基础[知识点]面向对象编程特点、程序设计环境[重难点]1.教学重点C++程序的编写和实现2.教学难点(1)面向对象编程特点(2)C++上机实践[教学内容](1)程序设计语言的发展:讲解机器语言到高级语言的特点(2)面向对象编程:讲解程序设计的范式(过程型、面向对象型)(3)C++的特点:高级语言(4)C++程序的构成和书写形式:程序结构、书写规范(5)C++程序设计和实现:程序设计各阶段的任务(6)程序设计环境:程序设计的实例[教学要求](1)对面向对象概念只作概念性的描述,无需深入讲解(2)以实例讲解C++程序特点和程序设计环境第2章基本数据类型与运算符[知识点]数据类型、运算符[重难点]1.教学重点C++的运算符2.教学难点表达式的书写与计算[教学内容](1)C++的数据类型(2)常量与变量(3)C++的运算符[教学要求]要求学生熟练掌握运算符及其优先级第3章程序控制[知识点]结构化程序设计、结构控制语句[重难点]1.教学重点(1)C++的输入与输出(2)关系运算和逻辑运算(3)选择结构和if语句(4)条件运算符和条件表达式(5)多分支选择结构和switch语句(6)循环结构和循环语句(7)循环的嵌套2.教学难点(1)多分支选择结构和switch语句(2)循环的嵌套[教学内容](1)C++程序和语句(2)C++的输入与输出(3)关系运算和逻辑运算(4)选择结构和if语句(5)条件运算符和条件表达式(6)多分支选择结构和switch语句(7)循环结构和循环语句(8)循环的嵌套(9)break语句和continue语句[教学要求](1)要求学生掌握程序设计环境的使用方法,能独立进行程序设计。

派生类的构造函数赋值和析构函数执行顺序

派生类的构造函数赋值和析构函数执行顺序

派生类的构造函数赋值和析构函数执行顺序基类的构造函数和析构函数是不能被继承的1、如果基类没有定义构造函数,派生类也可以不定义构造函数,使用默认的构造函数,其新增成员的初始化可以用其他公有函数来实现.2.如果基类中定义了缺省构造函数或根本没有定义任何一个构造函数(此时,由编译器自动生成缺省构造函数)时,在派生类构造函数的定义中可以省略对基类构造函数的调用,即省略<基类名>(<参数表>)。

3、如果基类定义了带有形参表的构造函数派生类就必须加入新的构造函数,提供一个将参数传递给基类构造函数的途径,保证在基类进行初始化时能够获得必要的数据因此,如果基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。

4.对派生类对象的清理工作也需要加入新的析构函数。

5. 子对象的情况与基类相同。

派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括其他类的对象(子对象),派生类的数据成员中实际上还间接包括了这些对象的数据成员。

因此,构造派生类的对象时,必须对基类数据成员、新增数据成员和成员对象的数据成员进行初始化。

派生类的构造函数必须要以合适的初值作为参数,隐含调用基类和新增对象成员的构造函数,来初始化它们各自的数据成员,然后再加入新的语句对新增普通数据成员进行初始化。

派生类构造函数的一般格式如下:<派生类名>::<派生类名>(<参数表>) : <基类名1>(<参数表1>),……,<基类名n>(<参数表n>),<子对象名1>(<参数表n+1>),……,<子对象名m>(<参数表n+m>){派生类新增成员的初始化函数语句;}说明:(1) 对基类成员和子对象成员的初始化必须在成员初始化列表中进行,新增成员的初始化既可以在成员初始化列表中进行,也可以在构造函数体中进行。

python 类析构函数

python 类析构函数

python 类析构函数Python是一种高级编程语言,支持多种编程范式,包括面向对象编程思想。

在Python中,类是一种用户自定义的数据类型,它封装了数据和行为,并提供了访问和操作这些数据的接口。

类的构造函数和析构函数是两个十分重要的概念,其中析构函数扮演着释放资源的角色。

本文将详细介绍Python中的类析构函数。

1、类的构造函数和析构函数在Python中,类的构造函数是指在创建类的实例时自动被调用的函数。

构造函数的作用是初始化实例变量。

在Python中,构造函数为__init__(self),它的第一个参数self指向类的实例对象本身。

而析构函数则是当类的实例对象被销毁时自动调用的函数。

析构函数的作用是释放实例占用的资源。

在Python 中,析构函数为__del__(self)。

2、析构函数的使用在Python中,类的析构函数可以用来释放一些资源,比如关闭文件、关闭数据库连接、释放内存等。

当类的实例对象被销毁时,Python会自动调用它的析构函数。

我们可以通过实现类的析构函数来释放一些资源,从而避免资源泄漏。

下面是一个简单的例子,展示了如何在Python中使用析构函数:class MyClass: def __init__(self): print("构造函数被调用")def __del__(self): print("析构函数被调用")obj = MyClass() del obj 输出结果为:构造函数被调用析构函数被调用在上面的例子中,我们创建了一个名为MyClass的类,并实现了它的构造函数和析构函数。

当我们创建了一个名为obj的MyClass类的实例对象时,构造函数被调用并输出“构造函数被调用”的信息。

当我们调用del语句删除实例对象时,Python会自动调用析构函数并输出“析构函数被调用”的信息。

3、注意事项在Python中,析构函数不是被立即调用的。

类的析构函数

类的析构函数

类的析构函数类的析构函数(Destructor)是类中的一种特殊成员函数,它在对象的生命周期结束时自动调用。

它的作用是释放类对象占用的内存空间、关闭相关资源和清除对象状态等。

因此,正确实现类的析构函数是保障程序数据完整性和稳定性的重要措施之一。

一、析构函数的命名和定义在C++中,类的析构函数的函数名必须与类名相同,只不过在函数名前面加上一个“~”(一个波浪号)。

例如,如果一个类名为“Test”,则析构函数的函数名应该是“~Test()”。

析构函数的定义在类的声明的下方,与构造函数类似,只不过在函数名前面加上一个“~”。

以下是一个简单的类的定义及其构造函数和析构函数的示例:``` class MyClass { public: MyClass(); // 构造函数 ~MyClass(); // 析构函数private: int *ptr; }; MyClass::MyClass(){ ptr = new int; } MyClass::~MyClass(){ delete ptr; } ```二、析构函数的特性1、在对象销毁时自动调用:析构函数在对象销毁时自动调用,不需要手动调用。

2、没有返回值和参数:析构函数没有返回类型和参数列表,因为它只是一个函数名和类名相同的函数。

3、只有一个析构函数:C++中只有一个析构函数,如果用户没有定义,默认的析构函数会执行对象的析构操作。

4、父类的析构函数:如果一个类继承了其他类,它的父类的析构函数也会被执行,这个过程被称为析构函数的“递归调用”。

5、虚析构函数:在当我们希望子类的析构函数能够释放掉子类中已经被分配的空间时,需要定义虚析构函数,这样在销毁时就可以调用子类的析构函数。

三、析构函数的常见问题和注意点1、构造函数与析构函数的区别:构造函数在对象创建时被自动调用,而析构函数则是在对象销毁时被自动调用。

构造函数的目的是初始化对象的成员数据,而析构函数的目的是清除对象的状态或占用资源。

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)。
12.
构造函数有个特殊的初始化方式叫 “初始化表达式表 ”(简称初始化表) 。初始化表 位于函数参数表之后,却在函数体 {} 之前。这说明该表里的初始化工作发生在函数体 内的任何代码被执行之前。 构造函数初始化表的使用规则: � 如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数。 例如 class A {… A(int x); }; class B : public A {… B(int x, int y);// B 的构造函数 }; B::B(int x, int y) : A(x) // 在初始化表里调用 A 的构造函数 // A 的构造函数
.4 示例:类 String 的构造函数与析构函数 13 13.
// String 的普通构造函数 String:: String(const char *str) { if(str==NULL) { m_data = new char[1];
*m_data = ‘\0 ’ ; } else { int length = strlen(str); m_data = new char[length+1]; strcpy(m_data, str); } } // String 的析构函数 String:: ~String(void) { delete [] m_data; // 由于 m_data 是内部数据类型,也可以写成 delete m_data; }
对于内部数据类型的数据成员而言,两种初始化方式的效率几乎没有区别,但后者 的程序版式似乎更清晰些。若类 F 的声明如下:
class F { public: F(int x, int y); private: int m_x, m_y; int m_i, m_j; } 示例 13-2(c)中 F 的构造函数采用了第一种初始化方式, 示例 13-2(d)中 F 的构造函 数采用了第二种初始化方式。 F::F(int x, int y) : m_x(x), m_y(y) { m_i = 0; m_j = 0; } }
第十三章 类的构造、析构与赋值函数
构造函数、析构函数与赋值函数是每个类最基本的函数。它们太普通以致让人容易 麻痹大意,其实这些貌似简单的函数就象没有顶盖的下水道那样危险。 每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝 构造函数, 其它的称为普通构造函数) 。 对于任意一个类 A, 如果不想编写上述函数, C++ 编译器将自动为 A 产生四个缺省的函数,如 A(void); A(const A &a); ~A(void); // 缺省的无参数构造函数 // 缺省的拷贝构造函数 // 缺省的析构函数
{ … } � 类的 const 常量只能在初始化表里被初始化,因为它不能在函数体内用赋值的方式 来初始化(参见 12.4 节 ) 。 � 类的数据成员的初始化可以采用初始化表或函数体内 赋值两种方式,这两种方式的 效率不完全相同。 非内部数据类型的成员对象应当采用第一种方式初始化,以获取更高的效率。例如 class A {… A(void); A(const A &other); }; class B { public: B(const A &a); // B 的构造函数 private: A }; 示例 13-2(a)中,类 B 的构造函数在其初始化表里调用了类 A 的拷贝构造函数,从 而将成员对象 m_a 初始化。 示例 13-2 (b)中, 类 B 的构造函数在函数体内用赋值的方式将成员对象 m_a 初始化 。 我们看到的只是一条赋值语句,但实际上 B 的构造函数干了两件事:先暗地里创建 m_a 对象(调用了 A 的无参数构造函数) ,再调用类 A 的赋值函数,将参数 a 赋给 m_a。 B::B(const A &a) : m_a(a) { … }
String & operate =(const String &other); // 赋值函数
.1 构造函数与析构函数的起源 13 13.
作为比 C 更先进的语言, C++ 提供了更好的机制来增强程序的安全性。 C++ 编译器
具有严格的类型安全检查功能,它几乎能找出程序中所有的语法问题,这的确帮了程序 员的大忙。但是程序通过了编译检查并不表示错误已经不存在了,在 “错误”的大家庭 里, “语法错误”的地位只能算是小弟弟。级别高的错误通常隐藏得很深,就象狡猾的 罪 犯,想逮住他可不容易。 根据经验,不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成的, 而初始化和清除工作很容易被人遗忘。 Stroustrup 在设计 C++ 语言时充分考虑了这个问 题 并很好地予以解决: 把对象的初始化工作放在构造函数中,把清除工作放在析构函数中。当对象被创建 时,构造函数被自动执行。当对象消亡时,析构函数被自动执行。这下就不用担心忘了 对象的初始化和清除工作。 构造函数与析构函数的名字不能随便起,必须让编译器认得出才可以被自动执行。 Stroustrup 的命名方法既简单又合理: 让构造函数、析构函数与类同名,由于析构函数的目的与构造函数的相反,就加前 缀 ‘~’ 以示区别 。 除了名字外,构造函数与析构函数的另一个特别之处是没有返回值类型,这与返回 值类型为 void 的函数不同。构造函数与析构函数的使命非常明确,就象出生与死亡,光 溜溜地来光溜溜地去。如果它们有返回值类型,那么编译器将不知所措。为了防止节外 生枝,干脆规定没有返回值类型。 (以上典故参考了文献 [Eekel, p55-p56] )
示例 13-2(a) 成员对象在初始化表中被初始化
// 无参数构造函数 // 拷贝构造函数 // 赋值函数
A & operate =( const A &other);
m_a;
// 成员对象
B::B(const A &a) { m_a = a; … }
示例 13-2(b) 成员对象在函数体内被初始化
.5 不要轻视拷贝构造函数与赋值函数 13 13.
由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数 有些轻视。请先记住以下的警告,在阅读正文时就会多心: � 本章开头讲过,如果不主动编写拷贝构造函数和赋值函数,编译器将以 “位拷贝” 的方式自动生成缺省的函数。 倘若类中含有指针变量,那么这两个 缺省的函数就隐 含了错误。以类 String 的两个对象 a,b 为例,假设 a.m_data 的内容为“hello”, b.m_data 的内容为“world”。 现将 a 赋给 b,缺省赋值函数的“位拷贝”意味着执行 b.m_data = a.m_data。 这将 造 成 三 个 错 误 : 一 是 b.m_data 原有 的 内 存 没 被 释 放 , 造 成 内 存 泄 露 ; 二 是 b.m_data 和 a.m_data 指向同一块内存,a 或 b 任何一方变动都会影响另一方;三是 在对象被析构时,m_data 被释放了两次。 � 拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对 象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三 个语句和第四个语句很相似,你分得清楚哪个 调用了拷贝构造函数, 哪个调用了赋 值函数吗? String String String a( “ hello ”); b( “ world ”); c = a; // 调用了拷贝构造函数,最好写成 c(a); c = b; // 调用了赋值函数 本例中第三个语句的风格较差,宜改写成 String c(a) 以区别于第四个语句。
A & operate =(const A &a); // 缺省的赋值函数 这不禁让人疑惑,既然能自动生成函数,为什么还要程序员编写? 原因如下: ( 1 )如果使用“缺省的无参数构造函数”和“缺省的析构函数”,等于放弃了自主“初 始化”和“清除”的机会,C++发明人 Stroustrup 的好心好意白费了。 ( 2 )“缺省的拷贝构造函数 ”和“缺省的赋值函数”均采用“位拷贝”而非“值拷贝” 的方式来实现,倘若类中含有指针变量,这两个函数注定将出错。 对于那些没有吃够苦头的 C++ 程序员,如果他说编写构造函数、析构函数与赋值函 数很容易,可以不用动脑筋,表明他的认识还比较肤浅,水平有待于提高。 本章以类 String 的设计与实现为例,深入阐述被很多教科书忽视了的道理。 String 的结构如下: class String { public: String(const char *str = NULL); String(const String &other); ~ String(void); private: char }; *m_data; // 用于保存字符串 // 普通构造函数 // 拷贝构造函数 // 析构函数
.6 示例:类 String 的拷贝构造函数与赋值函数 13 13.
// 拷贝构造函数 String::String(const String &other) { // 允许操作 other 的私有成员 m_data int length = strlen(other.m_data); m_data = new char[length+1]; strcpy(m_data, other.m_data); } // 赋值函数 String & String::operate =(const String &other) { // (1) 检查自赋值 if(this == &other) return *this; // (2) 释放原有的内存资源 delete [] m_data; // (3)分配新的内存资源,并复制内容 int length = strlen(other.m_data); m_data = new char[length+1]; strcpy(m_data, other.m_data); // (4)返回本对象的引用 return *this; } 类 String 拷贝构造函数与普通构造函数(参见 13.4 节)的区别是:在函数入口处 无 需与 NULL 进行比较,这是因为 “引用”不可能是 NULL,而“指针”可以为 NULL。 类 String 的赋值函数比构造函数复杂得多,分四步实现: ( 1 )第一步,检查自赋值。你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这 样的自赋值语句!的确不会。但是间接的自赋值仍有可能出现,例如 // 内容自赋值 b = a; … // 地址自赋值 b = &a; …
相关文档
最新文档