关于类和对象的进一步讨论之析构函数 C++
析构函数也是一个特殊的成员函数。它的作用与构造函数相反。它的名字是在类名的前面加一个“~”符号。在C++中“~”是位取反运算符。当对象的生命结束时,会自动执行解析函数。以下几种情况会执行析构函数:
1.如果在一个函数中定义了一个对象,当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
2.static局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数时,才调用staitic局部对象的析构函数。
3.如果定义了一个全局对象,则在程序的流程离开其作用域时(如main函数结束或exit函数),调用该全局对象的析构函数。
4.如果用new运算符动态的建立一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新的对象使用。程序设计者事先设计好析构函数,以完成所需的功能,只要对象的生命结束,程序就自动执行析构函数来完成这些工作。
析构函数不返回任何值,没有函数类型,也没有函数参数。由于没有函数参数,它不能被重载。并且一个类中只能有一个析构函数。
析构函数还可以被用来执行“用户希望在最后一次使用对象之后所执行的任何操作”。例如输出有关的信息。这里说用户是指类的设计者。析构函数可以完成设计者多指定的任何操作。
想让析构函数完成任何工作,都必须在定义的析构函数中指定。
调用构造函数和析构函数的顺序
在一般情况下,调用析构函数的次序正好与调用调用构造函数的次序相反,最先被调用的构造函数,其对应的析构函数最后被调用,而而最后调用的构造函数,其对应的析构函数最先被调用。先构造的后析构,后构造的先析构。(并非任何时候都是按照这一原则进行的。会在作用域和存储类别的概念方面的不同)。对象可以在不同的作用域中定义,但是这是有区别的。
下面归纳一下是什么时候调用构造函数和析构函数:
1.在全局范围内定义的对象(即在所有函数之外定义的对象),它的构造函数在文件中所有函数(包括main函数)执行之前调用。但是如果一个程序中有多 个文件,而不同的文件都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数(此时程序终止)时,调 用析构函数。
2.如果定义的是局部自动对象(例如在函数中定义对象),则在建立对象时调用其构造函数。如果函数被调用多次,则在每次建立对象时都要调用构造函 数。在函数调用结束、对象释放时先调用析构函数。
3.如果在函数中定义静态static局部对象,则只在程序第一次调用此函数建立对象时调用构造函数一次,在调用结束时对像并不释放,因此也不调用析构 函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。
对象数组
在建立数组时,同样要调用构造函数,如果有50个元素,需要调用50次构造函数。在需要时可以在定义数组时提供实参以实现初始化。如果构造函数只有一 个参数,在定义数组时可以直接在等号后面的花括号里提供实参。如
Student stud[3]={60,70,80};
如果构造函数有多个参数,则不能在定义数组时直接提供所有实参的方法,因为一个数组有多个元素,对每个元素提供多个实参,如果在考虑到构造函数有默 认参数的情况,很容易造成实参和形参的对应关系不清晰,出现歧义。
那么,如果构造函数有多个参数,在定义对象数组时应该怎么实现初始化呢?答案:在花括号中分别写出构造函数并指定实参,如果构造函数有3个参数,分 别代表学号、年龄、成绩。则可以这样定义数组:
Student stud[3]={ //定义对象数组
Student(1001,19,87); // 调用第一个元素的构造函数,为他提供三个参数
Student(1002,19,78); //调用第二个元素的构造函数,为他提供3个参数
Student(1003,18,79); // .......................
};
例子:
#include <iostream>
using namespace std;
class Box
{
public:
Box(int h,int w,int len):height(h),width(w),length(len){}
int volume();
private:
int height;
int width;
int length;
};
int Box::volume()
{
return (height*width*length);
}
int main()
{
Box a[3]={Box(10,12,15),Box(15,18,20),Box(16,20,26)};
cout<<"volume of a[0] is "<<a[0].volume()<<endl;
cout<<"volume of a[1] is "<<a[1].volume()<<endl;
cout<<"volume of a[2] is "<<a[2].volume()<<endl;
return 0;
}
对象指针
指向对象的指针,对象空间的起始地址就是对象的指针。
类名 *对象指针名;
指向对象成员的指针,对象有指针,存放对象初始地址的指针变量就是指向对象的指针变量。对象中的成员也有地址,存放对象成员地址的指针变量就是指 向对象成员的指针变量。
定义指向对象数据成员的指针变量的方法和定义指向普通变量的指针变量方法相同,例如:int *p;
定义指向对象数据成员和指针变量的一般形式:
数据类型名 *指针变量;
如果Time类的数据成员hour为公用的整数数据,则可以在类外通过指向对象数据成员的指针变量访问对象数据成员hour。
p1=&t1.hour;
cout<<*p1<<endl;
指向对象成员函数的指针,定义指向对象成员函数的指针变量的方法和定义指向普通函数的指针变量方法有所不同。下面是普通函数的指针变量的定义方 法: 数据类型名 (*指针变量名)(参数列表);
如:void (*p)(); //p是指向void型函数的指针变量
可以使它指向一个函数,并通过指针变量调用该函数。
p=fun; //将fun函数的入口地址赋给指针变量p,p就指向了函数fun
(*p)(); //调用fun函数
成员函数与普通函数一个最根本区别是:它是类中的一个成员。编译系统要求在上面的赋值语句中,指针变量的类型必须与赋值号右侧函数的类型相匹配,要 求以下3方面都要匹配:1.函数参数的类型和参数个数;2.函数返回值的类型;3.所属的类。
应该按照如下形式定义指向成员函数的指针变量:
void(Time::*p2)(); //定义p2为指向Time类中公用成员函数的指针变量。
注意:(Time::*p2)两侧的括号不能省略,因为()的优先级高于*。
定义指向公用成员函数的指针变量的一般形式是:
数据类型名 (类名::*指针变量名)(参数列表);
可以让它指向一个公用成员函数,只需要把公用成员函数的入口地址赋给一个指向公用成员函数的指针变量即可。例如:
p2=&Time::get_time;
使指针变量指向一个公用成员函数的一般形式:
指针变量名=&类名::成员函数名;
例子:
#include <iostream>
using namespace std;
class Time
{
public:
Time(int,int,int);
int hour;
int minute;
int sec;
void get_time();
};
Time::Time(int h,int m,int s)
{
hour=h;
minute=m;
sec=s;
}
void Time::get_time()
{
cout<<hour<<":"<<minute<<":"<<sec<<endl;
}
int main()
{
Time t1(15,12,55);
int *p1=&t1.hour;
cout<<*p1<<endl;
t1.get_time();
Time *p2=&t1;
p2->get_time();
void(Time::*p3)();
p3=&Time::get_time;
(t1.*p3)();
}
关于类和对象的进一步讨论之析构函数 C++的更多相关文章
- 关于类和对象的进一步讨论 C++
如果一个类中所有成员函数都是公用的,则可以在定义对象时对数据成员进行初始化: class Time { public: hour; minute; sec; }; Time t1={14,15,23 ...
- oc语言学习之基础知识点介绍(二):类和对象的进一步介绍
一.类.对象在内存中的存储 /* 内存分区: 栈:局部变量 堆:程序员自己写代码申请开辟的 程序员自己维护,编译器现在帮我们自动优化了,它在合适的给我们加上了释放空间的语句,所以我们现在写的对象不会造 ...
- C#学习笔记(十一):类和对象
面向对象 为什么要面向对象: 1.和函数一样,把算法封装起来,方便复用 2.更好理解自己和别人写的代码 封装:数据.结构.逻辑的封装,方便复用 多态:同一个对象,同一种指令,不同的行为(反应) 继承: ...
- PHP -- 类和对象基础入门
本文目录: 创建简单类和对象 继承 抽象类 接口 构造方法 析构函数 1. 创建简单类 创建一个People的类,在这里有四个要点说明一下: 第一个是在PHP中,访问属性 ...
- 《Java从入门到失业》第四章:类和对象(4.3):一个完整的例子带你深入类和对象
4.3一个完整的例子带你深入类和对象 到此为止,我们基本掌握了类和对象的基础知识,并且还学会了String类的基本使用,下面我想用一个实际的小例子,逐步来讨论类和对象的一些其他知识点. 4.3.1需求 ...
- 一文讲全了Python 类和对象内容
摘要:这是一个关于 Python 类和对象的全部内容. 本文分享自华为云社区<从零开始学python | Python 类和对象-面向对象编程>,原文作者:Yuchuan . Pytho ...
- Objective-C Runtime 运行时之一:类与对象
Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一 ...
- 解析Java类和对象的初始化过程
类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...
- iOS RunTime运行时(1):类与对象
Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下 ...
随机推荐
- (5.2.1)配置服务器参数——即时文件初始化(IFI)
关键词:零填充,即时文件初始化 转自:https://www.cnblogs.com/gaizai/p/3516905.html 概念: 所有新申请的空间,sql server都要以0来填充完磁盘文件 ...
- JavaFX桌面应用开发-鼠标事件和键盘事件
鼠标相关事件的操作初始代码 package application; import javafx.application.Application;import javafx.event.ActionE ...
- 【转】resultMap详解(包含多表查询)
简介: MyBatis的每一个查询映射的返回类型都是ResultMap,只是当我们提供的返回类型属性是resultType的时候,MyBatis对自动的给我们把对应的值赋给resultType所指定对 ...
- linu下nginx的安装
这里用到的环境是nginx-1.8.0,linux用的是CentOS-7-x86_64-DVD-1804.iso版本 1 什么是nginx Nginx ("engine x") ...
- c++ map: 使用struct或者数组做value
Notice 如果是program中有两个map对象,可能你需要两个map iterator,但是注意两个iter object不能命名一样,可以分别为iter1, iter2 Example #in ...
- 数据结构与算法(5) -- deque
vector是单向开口的连续线性空间,deque则是一种双向开口的连续线性空间.所谓双向开口,意思是可以在头尾两端分别做元素的插入和删除操作.stl中deque与vector最大的差异,一在于dequ ...
- C++字符串处理函数
#include<iostream> #include<stdlib.h> #include<string> #include <assert.h> u ...
- _initialize() 区别 __construct()
_initialize()方法是在任何方法执行之前,都要执行的,当然也包括 __construct构造函数. 也就是说如果存在_initialize()函数,调用对象的任何方法都会导致_initial ...
- BZOJ 1572 USACO 2009 Open 工作安排
先把工作按照Deadline从小到大排序 然后按顺序取,deadline大于现在总用时就取,等于现在总用时就从前面已取的工作中找一个P最小的同它比较,取P较大的一个 用优先队列维护已取工作中P的最小值 ...
- Django——13 Auth系统 登陆注册实例 权限的实现
Django Auth系统中的表 注册登陆实例 权限的实现 登陆权限 操作权限 组操作 Auth系统中的表 从表的名称我们就能看出,auth_user,auth_group,auth_permiss ...