16:29:32 第四章对象的初始化与销毁:构造函数与析构函数 本章主要内容: 1.构造函数、拷贝构造函数 重点 2.构造函数的初始化列表 难点 3.析构函数 重点 总体要求 理解构造函数与析构函数的必要性与特殊性,掌握它们的 使用方法
16:29:32 第四章 对象的初始化与销毁:构造函数与析构函数 本章主要内容: 1. 构造函数、拷贝构造函数 —— 重点 2. 构造函数的初始化列表 —— 难点 3. 析构函数 —— 重点 总体要求: 理解构造函数与析构函数的必要性与特殊性,掌握它们的 使用方法
6:29:3 §1对象的初始化 实质是对象中成员变量的初始化,有3种常见方法 1.成员变量全部公有时的初始化 类的成员变量都是公有的,此时对该类对象的初始化可以 与C中对结构体变量的初始化一样 class address t class person public: public long telenum char name [15] char addr [30] int age; address addr. person p1={“张三”,2 8911114,“ Lanzhou University”}}; 缺点: 数据完全外露,没有实现信息隐藏
16:29:32 §1 对象的初始化 1.成员变量全部公有时的初始化 类的成员变量都是公有的,此时对该类对象的初始化可以 与C中对结构体变量的初始化一样 class person{ public: char name[15]; int age; address addr; }; class address{ public: long telenum; char addr[30]; }; person p1={ “张三”,23, {8911114,“LanZhou University”} }; 缺点: 数据完全外露,没有实现信息隐藏 – 实质是对象中成员变量的初始化,有3种常见方法
6:29:3 2.使用公有的成员函数完成对象的初始化 在类中提供公有的成员函数,对象通过调用这样的成员函 数对其内部的成员进行初始化 例:银行帐户类 class account void Account:: Initialize( char sName [32] char *name char *id char siD[20]: float amount float bAlance public: strcpy(sName, name) void Initialze(char * strcpy(sID, id) char *, float fBalance=amount: 缺点: 客户程序员容易忘记调用这样的函数,对象的初始化得 不到保障
16:29:32 2.使用公有的成员函数完成对象的初始化 在类中提供公有的成员函数,对象通过调用这样的成员函 数对其内部的成员进行初始化 例:银行帐户类 class Account{ char sName[32]; char sID[20]; float fBalance; public: void Initialze(char *, char *,float); }; void Account::Initialize( char *name,char *id, float amount ) { strcpy(sName,name); strcpy(sID,id); fBalance=amount; } void main(){ Account acc; acc.Initialize(“张三” , “s9801”,1000); } 缺点: 客户程序员容易忘记调用这样的函数,对象的初始化得 不到保障
6:29:3 3.构造函数( construc tor) 构造函数是类中特殊的成员函数,其函数名与类名相同 创建对象时系统自动调用构造函数 创建对象的两种方法: 定义类类型的变量 用new运算符动态产生对象 无论用那种方法,都会自动调用构造函数 不是由客户程序员人为调用,而是自动调用 把给成员变量赋值的操作写在构造函数中,就能初始化成 员变量:对象一旦被创建,马上调用构造函数,在能对对象 进行其它操作之前,对象的成员变量已有确定的值了 例:.银行帐户类 日期类
16:29:32 3.构造函数(constructor) –构造函数是类中特殊的成员函数,其函数名与类名相同 –创建对象时系统自动调用构造函数 创建对象的两种方法: .定义类类型的变量 .用new运算符动态产生对象 无论用那种方法,都会自动调用构造函数 —— 不是由客户程序员人为调用,而是自动调用 例: .银行帐户类 .日期类 – 把给成员变量赋值的操作写在构造函数中,就能初始化成 员变量:对象一旦被创建,马上调用构造函数,在能对对象 进行其它操作之前,对象的成员变量已有确定的值了
6:29:3 构造函数的必要性与特殊性 函数名与类名相同 在定义和声明时,不能说明构造函数的返回值类型,而且 构造函数根本不返回任何值 个类的构造函数可以有多个:构造函数允许重载,一个 构造函数对应一种创建对象的方法 构造函数可以带有形参,也可以不带形参,创建对象时自 动调用参数类型、数目均能匹配的一个。实参通过在创建 对象时用括号的形式,在括号中传递给形参。若调用的是 不带参的构造函数,则括号可省略。无论带参与否,程序 中都不能通过对象名或对象指针显式调用构造函数 例: Date dt0bj(2004,10,11) Date *pDtob j=new Date(2004, 10, 12) Date dtob jDf t; Date *pDt=new Da te
16:29:32 构造函数的必要性与特殊性 –函数名与类名相同 –在定义和声明时,不能说明构造函数的返回值类型,而且 构造函数根本不返回任何值 –一个类的构造函数可以有多个:构造函数允许重载,一个 构造函数对应一种创建对象的方法 –构造函数可以带有形参,也可以不带形参,创建对象时自 动调用参数类型、数目均能匹配的一个。实参通过在创建 对象时用括号的形式,在括号中传递给形参。若调用的是 不带参的构造函数,则括号可省略。无论带参与否,程序 中都不能通过对象名或对象指针显式调用构造函数 例:Date dtObj(2004,10,11); Date *pDtObj=new Date(2004,10,12); Date dtObjDft; Date *pDt=new Date;
6:29:32 构造函数的必要性与特殊性(续) 类中未显式提供构造函数时,C++会自动添加一个默认构造 函数,该构造函数不带有形参,且函数体为空,在后台起作用; 若类中显式提供了构造函数,则不再添加默认构造函数 使用默认构造函数的情况下,若创建的对象是全局对象或 静态对象,则成员变量的值全部被置为相应类型的0值,否 则成员变量的值不确定 应尽可能提供自己的构造函数,而不使用默认的构造函数
16:29:32 构造函数的必要性与特殊性(续) –类中未显式提供构造函数时,C++会自动添加一个默认构造 函数,该构造函数不带有形参,且函数体为空,在后台起作用; 若类中显式提供了构造函数,则不再添加默认构造函数 –使用默认构造函数的情况下,若创建的对象是全局对象或 静态对象,则成员变量的值全部被置为相应类型的0值,否 则成员变量的值不确定 –应尽可能提供自己的构造函数,而不使用默认的构造函数
§2拷贝构造函数(copy- constructor) 6:29:3 种特殊的构造函数 创建对象时,用一个已经存在的对象对新创建的同类对象 进行初始化,此时要求构造函数的参数为自身类类型的引 用,这种构造函数称为拷贝构造函数 拷贝构造函数的一般形式为 类名∷类名( cons t类名&引用名,) 般情况下,多使用如下形式 类名:类名( cons t类名&引用名); 其中 cons t是可选的 例:拷贝构造函数 class a public A(int)Icout < AO<< endl; A(const A&)(cout <<"A(A&, int)"<< end1; void maino a a(1): a b(a); Ac=b: 1
16:29:32 §2 拷贝构造函数(copy-constructor) –一种特殊的构造函数 –创建对象时,用一个已经存在的对象对新创建的同类对象 进行初始化,此时要求构造函数的参数为自身类类型的引 用,这种构造函数称为拷贝构造函数 –拷贝构造函数的一般形式为 类名::类名(const 类名& 引用名,…); 一般情况下,多使用如下形式 类名::类名(const 类名& 引用名); 其中const是可选的 例:拷贝构造函数 class A{ public: A(int){cout << "A()" << endl;} A(const A&){cout << "A(A&,int)" << endl;} }; void main(){A a(1);A b(a);A c=b;}
6:29:3 拷贝构造函数调用的时机 用已经存在的对象初始化新创建的对象时,调用拷贝构造 函数 例: Location类 对象做形参,调用函数时用实参对象初始化形参,调用拷 贝构造函数 void f (location p) cout< Functin:”<<p.getX0<“,”<p.getY0<endl;} 推荐使用对象的引用做形参,可降低函数调用过程中的开销 函数返回对象,此时要通过拷贝构造函数创建临时对象 Location g 0 Location A(1, 2); return A
16:29:32 拷贝构造函数调用的时机 –用已经存在的对象初始化新创建的对象时,调用拷贝构造 函数 例:Location类 –对象做形参,调用函数时用实参对象初始化形参,调用拷 贝构造函数 void f(Location p) {cout<<“Functin:”<<p.getX()<<“ , ”<<p.getY()<<endl;} 推荐使用对象的引用做形参,可降低函数调用过程中的开销 –函数返回对象,此时要通过拷贝构造函数创建临时对象 Location g() {Location A(1,2);return A;}
6:29:3 浅拷贝与深拷贝 类中未显式提供拷贝构造函数时,C++会自动添加一个默认 拷贝构造函数,该拷贝构造函数完成的功能是位对位的拷 贝,亦即将已存在对象中的每一位复制到新创建的对象中 对应的位(亦即将已存在对象中的每个成员拷贝到新建对象 中对应的成员),此时称完成的拷贝是浅拷贝 默认的拷贝构造函数在一般情况下可以很好地工作,但 些特殊情况下,仅使用默认的拷贝构造函数可能会引起问题 此时必须提供自己的拷贝构造函数并按需要自己完成拷贝 工作才能解决问题,称这时完成的拷贝是深拷贝 例:内部包含指针成员变量的类 浅拷贝 深拷贝 例:自动记录本类对象数目的类 浅拷贝 深拷贝
16:29:32 浅拷贝与深拷贝 –类中未显式提供拷贝构造函数时,C++会自动添加一个默认 拷贝构造函数,该拷贝构造函数完成的功能是位对位的拷 贝,亦即将已存在对象中的每一位复制到新创建的对象中 对应的位(亦即将已存在对象中的每个成员拷贝到新建对象 中对应的成员),此时称完成的拷贝是浅拷贝 –默认的拷贝构造函数在一般情况下可以很好地工作,但一 些特殊情况下,仅使用默认的拷贝构造函数可能会引起问题, 此时必须提供自己的拷贝构造函数并按需要自己完成拷贝 工作才能解决问题,称这时完成的拷贝是深拷贝 例:内部包含指针成员变量的类 .浅拷贝 .深拷贝 例:自动记录本类对象数目的类 .浅拷贝 .深拷贝