cppCH3构造函数与析构函数
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
14
拷贝构造函数--说明 • 当类中没有声明拷贝构造函数时,类中会 自动生成一个默认拷贝构造函数。实现 “浅拷贝”。这个默认拷贝构造函数执行 的功能是:用作为初始值的对象的每个数 据成员的值,初始化将要建立的对象的对 应数据成员。
18
•
• • • •
3.2 析构函数 析构函数的功能:当对象消失时,系统自动调 用析构函数,执行一些清理任务,例如释放由 构造函数分配的内存(new)。 3.2.1 定义析构函数 3.2.2 析构函数和对象数组 3.2.3 析构函数和运算符delete 3.2.4 缺省析构函数
3.1构造函数2
2、对象的创建 • 普通对象的创建(举例理解) • 对象数组的创建(举例理解1、举例理解2 ) 3、外部对象的引用性说明(举例理解) 4、全局对象的创建(举例理解) 5、动态内存分配 • 动态对象的创建 • 动态对象数组的创建
6
3.1.3 缺省构造函数
1、缺省构造函数 不带参数的构造函数称作缺省构造函数。 • 例如: Test ::Test(){cout<<"Initializing default"<<endl;} 2、编译器生成缺省构造函数 • 如果程序员没有为声明的类义任何构造函数,则编译 器自动生成缺省构造函数 • 如果程序员已经为类定义任何构造函数,则编译器不 再自动生成缺省构造函数 • 编译器生成缺省构造函数举例: Test(){ } 3、若没有为类定义缺省构造函数时,则在说明对象 (对象数组)时必须提供初始值。 4、当声明对象时,一定要保证对象能够被恰当的构造 函数所创建。
2
3.0 初始化、赋值的概念
• 2、赋值 • 在执行语句中,使用”=”表示赋值。 • 赋值的一般形式: 左值=右值 • 例如:
int i; i=1; Location A(0,0),B; B=A;
3
• 在C++语言中,可以使用初始化列表给没有定义构造 函数的类的对象进行初始化。 • 例如: #include<iostream.h> #include<iostream.h> class Point{ class Point{ public: public: int X,Y; int X,Y; Point(int x,int y) void display() {X=x;Y=y;} {cout<<X<<", " void display() <<Y<<endl;} {cout<<X<<","<<Y<<endl;} }; }; void main(){ void main(){ Point A={1,2}; Point A={1,2}; A.display(); A.display(); } } • 有构造函数时,使用初始化列表则错 • 当数据成员的访问控制权限为私有时,使用初始化列 表错 4
33
19
3.2.1 定义析构函数 1、析构函数的特点:函数名、返回值、参数表 2、析构函数的行为:当对象生存期结束时,程 序为这个对象调用析构函数,然后收回这个对 象占用的内存。 3、全局对象和静态对象的析构函数在程序运行 结束之前调用。 4、当使用C++的系统函数exit终止一个程序运行 时,也调用全局对象和静态对象的析构函数。 • 举例理解:对象的创建和消亡(p44,test2.h— p43)
2编译器生成缺省构造函数如果程序员没有为声明的类义任何构造函数则编译器自动生成缺省构造函数如果程序员已经为类定义任何构造函数则编译器不再自动生成缺省构造函数编译器生成缺省构造函数举例
cppCH3构造函数与析构函数
自考
1
3.0 初始化、赋值的概念 1、初始化 • 声明标识符(变量、对象、引用名)的同 时给初值成为初始化。 • 初始化的一般格式: 数据类型 标识符=初始值 或 数据类型 标识符(初始值) • 例如: int i=0;或 int i(0); Location A(0,0);
26
3、构造函数的类型转换功能
• 建立对象方式: • 1、形如: Test Try=5;//被编译器解释为Test Try(5); Test Try=Test(5,'B');//被编译器解释为Test Try(5,'B'); 这里调用构造函数创建对象。 • 2、形如: Test Try2=Try1; //被编译器解释为Test Try2(Try1); 这里调用拷贝构造函数创建对象。 • 注意: Test Try=5,‘B’;//错 Test Try=(5,'B');//被编译器解释为Test Try('B'); • 在哪些情况下,程序员必须定义拷贝构造函数? 答:当在构造函数中分配使用了系统资源,例如使用 new分配了内存,这时必须定义拷贝构造函数,”=” 重载函数;析构函数中还要释放这些资源,例如使用 delete。
25
• Try=Test(10);这个操作,是否合法取决于Test类当中 有没有具有类型转换功能的构造函数。
#include<iostream.h> class Test{ private: int num; char c; public: Test(int n=0,char c='\0'){ num=n;Test::c=c; cout<<"Initializing..."<<num<<this->c<<endl; } void print(){cout<<num<<" "<<c<<endl;} ~Test(){cout<<"Destructing..."<<num<<c<<endl;} }; void main(){ Test Try; Try=Test(10,'A'); Try.print(); }
29
Try2=Try1;被编译器解释为Try2.operator=(Try1);
3.5 对象赋值—理解赋值号重载函数 • 缺省赋值号重载函数形式和作用(p52) • 自定义赋值号重载函数形式 • 举例理解(p53)
30
• 对象成员:在一个类中说明具有类类型的数据成员, 这些成员称为对象成员。含有对象成员的类,称为组 合类。 • 说明对象成员的一般形式(p55) • 组合类的构造函数的定义形式(p55):对象成员所需的 参数要在组合类的构造函数的初始化列表中给出。 • 对象成员的初始化(构造函数的调用)顺序取决于这 些对象成员在类中说明的顺序,与他们在成员初始化 列表中给出的顺序无关。 • 组合类对象构造函数调用的顺序:当建立组合类的对 象时,先调用对象成员的构造函数,初始化对象成员, 然后才执行组合类的构造函数的函数体,初始化组合 类中的其它普通数据成员。 • 组合类对象析构函数调用的顺序:与构造函数的调用 顺序严格相反。 • 举例理解(p55-56)
• Try=5;这个操作,是否合法取决于Test类当中有 没有具有类型转换功能的构造函数
24
2、P47-48 • 正确的注释如下: Initializing 0 //建立对象Try Initializing 5 //建立隐藏对象 Destroying 5 // 析构新建的隐藏对象 5 // 输出Try对象的数据 Initializing 10 //由强制类型转换建立数据为10的对象 Destroying 10 // 析构新建的隐藏对象Try(num=10) 10 // 输出Try对象的数据 Destroying 10 // 析构Try对象
27
3.4 对象的初始化1
•
• • •
3.4 对象的初始化2--再谈拷贝构造函数 缺省拷贝构造函数带来的问题:”浅拷贝 “ 举例理解(p49) 拷贝构造函数被调用的三种情况: 举例理解(p50)
28
3.5 对象赋值 • 1、先来看一个例子:
#include<iostream.h> class Test{ private: int num; char c; public: Test(int n=0,char c='\0'){ num=n;Test::c=c; cout<<"Initializing..."<<num<<this->c<<endl; } void print(){cout<<num<<" "<<c<<endl;} ~Test(){cout<<"Destructing..."<<num<<c<<endl;} }; void main(){ Test Try1(5,'B'); Test Try2 Try2=Try1; Try2.print(); }
13
3.1.4 复制初始化构造函数 • 赋制初始化构造函数:又称作拷贝构造函数。 • 拷贝构造函数的一般语法形式: 类名::类名(类名 &r){ …… } • 在拷贝构造函数中通过对象引用访问私有成员 是允许的。 • 拷贝构造函数会在如下三种情况下被调用: (1)当用一个类的对象去初始化另一个对象时; (2)如果函数的形参是类的对象,调用函数时, 进行形参和实参结合时; (3)如果函数的返回值是类的对象,函数执行完 成返回调用者时
22
3.2.4 缺省析构函数 • 当定义类时没有定义析构函数,C++编译器 会为这个类自动产生一个缺省析构函数。 • 编译器自动产生的缺省析构函数形式如下: 类名::~类名(){} • 它的函数体是空的,即这个析构函数什么 都不做。 • 当这个类的对象生存期结束时,系统会自 动来调用这个析构函数。
23
• 1、首先来看一个示例程序
3.3 构造函数的类型转换
#include<iostream.h> class Test{ private: int num; public: Test(int n=0){ num=n; cout<<"Initializing..."<<num<<endl; } void print(){cout<<num<<endl;} ~Test(){cout<<"Destructing..."<<num<<endl;} }; void main(){ Test Try(0); Try=5; Try.print(); Try=Test(10); Try.print(); }
31
3.6 对象成员
习题3
• • • • • • • •
一、填空题 二、选择题 三、改错题 四、分析程序题 1、 2、 3、 五、完成程序
32
4-2 分析下面程序设计思想及输出结果
#include<iostream.h> class number{ private: int val; public: number(int i){val=i;} operator int(){return val;} }; /*class num:public number{ public: num(int i):number(i){} }; */ void main(){ number n(55); int i=n; cout<<i+n<<endl; }
20
3.2.2 析构函数和对象数组 • 对象数组的创建:C++系统为每个对象数组 元素调用构造函数 • 对象数组的生命期结束时,C++系统为每个 对象数组元素调用析构函数。 • 举例理解(p45,test2.h—p43)
21
•
• • •
3.2.3 析构函数和运算符delete 运算符delete删除一个对象时,它首先为这 个动态对象调用析构函数,然后再释放这 个对象占用的内存,这和使用new建立对象 的过程正好相反。 举例理解(p46,test2.h—p43) 普通动态对象的建立和删除 动态对象数组的建立和删除
3.1 构造函数1
1、定义构造函数
1、构造函数的特点: (1)构造函数是和类名同名的成员函数; (2)定义构造函数时不能指定返回值类型; (3)当声明对象时,构造函数被系统自动调用来初始 化对象。 #include<iostream.h> class Location{ private: int X,Y; public: Location(){X=Y=0;} Location(int x,int y){X=x;Y=y;} int GetX(){return X;} int GetY(){return Y;} }; void main(){ Location A1(6,8); cout<<A1.GetX()<<","<<A1.GetY()<<endl; } 5
拷贝构造函数--说明 • 当类中没有声明拷贝构造函数时,类中会 自动生成一个默认拷贝构造函数。实现 “浅拷贝”。这个默认拷贝构造函数执行 的功能是:用作为初始值的对象的每个数 据成员的值,初始化将要建立的对象的对 应数据成员。
18
•
• • • •
3.2 析构函数 析构函数的功能:当对象消失时,系统自动调 用析构函数,执行一些清理任务,例如释放由 构造函数分配的内存(new)。 3.2.1 定义析构函数 3.2.2 析构函数和对象数组 3.2.3 析构函数和运算符delete 3.2.4 缺省析构函数
3.1构造函数2
2、对象的创建 • 普通对象的创建(举例理解) • 对象数组的创建(举例理解1、举例理解2 ) 3、外部对象的引用性说明(举例理解) 4、全局对象的创建(举例理解) 5、动态内存分配 • 动态对象的创建 • 动态对象数组的创建
6
3.1.3 缺省构造函数
1、缺省构造函数 不带参数的构造函数称作缺省构造函数。 • 例如: Test ::Test(){cout<<"Initializing default"<<endl;} 2、编译器生成缺省构造函数 • 如果程序员没有为声明的类义任何构造函数,则编译 器自动生成缺省构造函数 • 如果程序员已经为类定义任何构造函数,则编译器不 再自动生成缺省构造函数 • 编译器生成缺省构造函数举例: Test(){ } 3、若没有为类定义缺省构造函数时,则在说明对象 (对象数组)时必须提供初始值。 4、当声明对象时,一定要保证对象能够被恰当的构造 函数所创建。
2
3.0 初始化、赋值的概念
• 2、赋值 • 在执行语句中,使用”=”表示赋值。 • 赋值的一般形式: 左值=右值 • 例如:
int i; i=1; Location A(0,0),B; B=A;
3
• 在C++语言中,可以使用初始化列表给没有定义构造 函数的类的对象进行初始化。 • 例如: #include<iostream.h> #include<iostream.h> class Point{ class Point{ public: public: int X,Y; int X,Y; Point(int x,int y) void display() {X=x;Y=y;} {cout<<X<<", " void display() <<Y<<endl;} {cout<<X<<","<<Y<<endl;} }; }; void main(){ void main(){ Point A={1,2}; Point A={1,2}; A.display(); A.display(); } } • 有构造函数时,使用初始化列表则错 • 当数据成员的访问控制权限为私有时,使用初始化列 表错 4
33
19
3.2.1 定义析构函数 1、析构函数的特点:函数名、返回值、参数表 2、析构函数的行为:当对象生存期结束时,程 序为这个对象调用析构函数,然后收回这个对 象占用的内存。 3、全局对象和静态对象的析构函数在程序运行 结束之前调用。 4、当使用C++的系统函数exit终止一个程序运行 时,也调用全局对象和静态对象的析构函数。 • 举例理解:对象的创建和消亡(p44,test2.h— p43)
2编译器生成缺省构造函数如果程序员没有为声明的类义任何构造函数则编译器自动生成缺省构造函数如果程序员已经为类定义任何构造函数则编译器不再自动生成缺省构造函数编译器生成缺省构造函数举例
cppCH3构造函数与析构函数
自考
1
3.0 初始化、赋值的概念 1、初始化 • 声明标识符(变量、对象、引用名)的同 时给初值成为初始化。 • 初始化的一般格式: 数据类型 标识符=初始值 或 数据类型 标识符(初始值) • 例如: int i=0;或 int i(0); Location A(0,0);
26
3、构造函数的类型转换功能
• 建立对象方式: • 1、形如: Test Try=5;//被编译器解释为Test Try(5); Test Try=Test(5,'B');//被编译器解释为Test Try(5,'B'); 这里调用构造函数创建对象。 • 2、形如: Test Try2=Try1; //被编译器解释为Test Try2(Try1); 这里调用拷贝构造函数创建对象。 • 注意: Test Try=5,‘B’;//错 Test Try=(5,'B');//被编译器解释为Test Try('B'); • 在哪些情况下,程序员必须定义拷贝构造函数? 答:当在构造函数中分配使用了系统资源,例如使用 new分配了内存,这时必须定义拷贝构造函数,”=” 重载函数;析构函数中还要释放这些资源,例如使用 delete。
25
• Try=Test(10);这个操作,是否合法取决于Test类当中 有没有具有类型转换功能的构造函数。
#include<iostream.h> class Test{ private: int num; char c; public: Test(int n=0,char c='\0'){ num=n;Test::c=c; cout<<"Initializing..."<<num<<this->c<<endl; } void print(){cout<<num<<" "<<c<<endl;} ~Test(){cout<<"Destructing..."<<num<<c<<endl;} }; void main(){ Test Try; Try=Test(10,'A'); Try.print(); }
29
Try2=Try1;被编译器解释为Try2.operator=(Try1);
3.5 对象赋值—理解赋值号重载函数 • 缺省赋值号重载函数形式和作用(p52) • 自定义赋值号重载函数形式 • 举例理解(p53)
30
• 对象成员:在一个类中说明具有类类型的数据成员, 这些成员称为对象成员。含有对象成员的类,称为组 合类。 • 说明对象成员的一般形式(p55) • 组合类的构造函数的定义形式(p55):对象成员所需的 参数要在组合类的构造函数的初始化列表中给出。 • 对象成员的初始化(构造函数的调用)顺序取决于这 些对象成员在类中说明的顺序,与他们在成员初始化 列表中给出的顺序无关。 • 组合类对象构造函数调用的顺序:当建立组合类的对 象时,先调用对象成员的构造函数,初始化对象成员, 然后才执行组合类的构造函数的函数体,初始化组合 类中的其它普通数据成员。 • 组合类对象析构函数调用的顺序:与构造函数的调用 顺序严格相反。 • 举例理解(p55-56)
• Try=5;这个操作,是否合法取决于Test类当中有 没有具有类型转换功能的构造函数
24
2、P47-48 • 正确的注释如下: Initializing 0 //建立对象Try Initializing 5 //建立隐藏对象 Destroying 5 // 析构新建的隐藏对象 5 // 输出Try对象的数据 Initializing 10 //由强制类型转换建立数据为10的对象 Destroying 10 // 析构新建的隐藏对象Try(num=10) 10 // 输出Try对象的数据 Destroying 10 // 析构Try对象
27
3.4 对象的初始化1
•
• • •
3.4 对象的初始化2--再谈拷贝构造函数 缺省拷贝构造函数带来的问题:”浅拷贝 “ 举例理解(p49) 拷贝构造函数被调用的三种情况: 举例理解(p50)
28
3.5 对象赋值 • 1、先来看一个例子:
#include<iostream.h> class Test{ private: int num; char c; public: Test(int n=0,char c='\0'){ num=n;Test::c=c; cout<<"Initializing..."<<num<<this->c<<endl; } void print(){cout<<num<<" "<<c<<endl;} ~Test(){cout<<"Destructing..."<<num<<c<<endl;} }; void main(){ Test Try1(5,'B'); Test Try2 Try2=Try1; Try2.print(); }
13
3.1.4 复制初始化构造函数 • 赋制初始化构造函数:又称作拷贝构造函数。 • 拷贝构造函数的一般语法形式: 类名::类名(类名 &r){ …… } • 在拷贝构造函数中通过对象引用访问私有成员 是允许的。 • 拷贝构造函数会在如下三种情况下被调用: (1)当用一个类的对象去初始化另一个对象时; (2)如果函数的形参是类的对象,调用函数时, 进行形参和实参结合时; (3)如果函数的返回值是类的对象,函数执行完 成返回调用者时
22
3.2.4 缺省析构函数 • 当定义类时没有定义析构函数,C++编译器 会为这个类自动产生一个缺省析构函数。 • 编译器自动产生的缺省析构函数形式如下: 类名::~类名(){} • 它的函数体是空的,即这个析构函数什么 都不做。 • 当这个类的对象生存期结束时,系统会自 动来调用这个析构函数。
23
• 1、首先来看一个示例程序
3.3 构造函数的类型转换
#include<iostream.h> class Test{ private: int num; public: Test(int n=0){ num=n; cout<<"Initializing..."<<num<<endl; } void print(){cout<<num<<endl;} ~Test(){cout<<"Destructing..."<<num<<endl;} }; void main(){ Test Try(0); Try=5; Try.print(); Try=Test(10); Try.print(); }
31
3.6 对象成员
习题3
• • • • • • • •
一、填空题 二、选择题 三、改错题 四、分析程序题 1、 2、 3、 五、完成程序
32
4-2 分析下面程序设计思想及输出结果
#include<iostream.h> class number{ private: int val; public: number(int i){val=i;} operator int(){return val;} }; /*class num:public number{ public: num(int i):number(i){} }; */ void main(){ number n(55); int i=n; cout<<i+n<<endl; }
20
3.2.2 析构函数和对象数组 • 对象数组的创建:C++系统为每个对象数组 元素调用构造函数 • 对象数组的生命期结束时,C++系统为每个 对象数组元素调用析构函数。 • 举例理解(p45,test2.h—p43)
21
•
• • •
3.2.3 析构函数和运算符delete 运算符delete删除一个对象时,它首先为这 个动态对象调用析构函数,然后再释放这 个对象占用的内存,这和使用new建立对象 的过程正好相反。 举例理解(p46,test2.h—p43) 普通动态对象的建立和删除 动态对象数组的建立和删除
3.1 构造函数1
1、定义构造函数
1、构造函数的特点: (1)构造函数是和类名同名的成员函数; (2)定义构造函数时不能指定返回值类型; (3)当声明对象时,构造函数被系统自动调用来初始 化对象。 #include<iostream.h> class Location{ private: int X,Y; public: Location(){X=Y=0;} Location(int x,int y){X=x;Y=y;} int GetX(){return X;} int GetY(){return Y;} }; void main(){ Location A1(6,8); cout<<A1.GetX()<<","<<A1.GetY()<<endl; } 5