析构函数也是一个特殊的成员函数。它的作用与构造函数相反。它的名字是在类名的前面加一个“~”符号。在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++的更多相关文章

  1. 关于类和对象的进一步讨论 C++

    如果一个类中所有成员函数都是公用的,则可以在定义对象时对数据成员进行初始化: class  Time { public: hour; minute; sec; }; Time t1={14,15,23 ...

  2. oc语言学习之基础知识点介绍(二):类和对象的进一步介绍

    一.类.对象在内存中的存储 /* 内存分区: 栈:局部变量 堆:程序员自己写代码申请开辟的 程序员自己维护,编译器现在帮我们自动优化了,它在合适的给我们加上了释放空间的语句,所以我们现在写的对象不会造 ...

  3. C#学习笔记(十一):类和对象

    面向对象 为什么要面向对象: 1.和函数一样,把算法封装起来,方便复用 2.更好理解自己和别人写的代码 封装:数据.结构.逻辑的封装,方便复用 多态:同一个对象,同一种指令,不同的行为(反应) 继承: ...

  4. PHP -- 类和对象基础入门

         本文目录:    创建简单类和对象 继承 抽象类 接口 构造方法 析构函数     1. 创建简单类    创建一个People的类,在这里有四个要点说明一下: 第一个是在PHP中,访问属性 ...

  5. 《Java从入门到失业》第四章:类和对象(4.3):一个完整的例子带你深入类和对象

    4.3一个完整的例子带你深入类和对象 到此为止,我们基本掌握了类和对象的基础知识,并且还学会了String类的基本使用,下面我想用一个实际的小例子,逐步来讨论类和对象的一些其他知识点. 4.3.1需求 ...

  6. 一文讲全了Python 类和对象内容

    摘要:这是一个关于 Python 类和对象的全部内容. 本文分享自华为云社区<从零开始学python | Python 类和对象-面向对象编程>,原文作者:Yuchuan  . Pytho ...

  7. Objective-C Runtime 运行时之一:类与对象

    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一 ...

  8. 解析Java类和对象的初始化过程

    类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...

  9. iOS RunTime运行时(1):类与对象

    Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下 ...

随机推荐

  1. registerDataSetObserver:浅析Andorid ListView和Adapte

    最近由于遇到将内容分部绑定到ListView里的需求,追踪源码之后对ListView和Adapter有了点肤浅的认识,在此与大家分享. 这里用到了观察者模式,在ListView的setAdapter里 ...

  2. iOS UIWebView 访问https绕过证书验证的方法

    @implementation NSURLRequest (NSURLRequestWithIgnoreSSL) + (BOOL)allowsAnyHTTPSCertificateForHost:(N ...

  3. python笔记之发送邮件

    发送邮件前提:开启邮箱授权码 一.开启授权码(以163邮箱为例) 1.登录163邮箱,点击设置--POP3/SMTP/IMAP,出现设置界面   2. 开启SMTP服务且可以查询SMTP的host地址 ...

  4. Requirejs常用配置和应用

    requirejs.require方法冲突 如果加载了多个requirejs脚本,每个requirejs会判断是否浏览器已经实现了require和define方法.如果浏览器已经自带require和d ...

  5. btrfs基础

    btrfs文件系统简介  btrfs文件系统:技术预览版(Centos7)  Btrfs(B-tree.Butter FS.Better FS),GPL授权,Orale2007提出是想用来取代Ext文 ...

  6. Django-----中间件Cookie

    Cookie: 用来跟踪用户的会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份. Cookie机制 ...

  7. vue 使用echarts

    import echarts from 'echarts'   <div id="kocGrow" style="width: 600px;height: 300p ...

  8. Beetl学习总结(3)——高级功能

    3.1. 配置GroupTemplate Beetl建议通过配置文件配置配置GroupTemplate,主要考虑到未来可能IDE插件会支持Beetl模板,模板的属性,和函数等如果能通过配置文件获取,将 ...

  9. Beetl学习总结(2)——基本用法

    2.1. 安装 如果使用maven,使用如下坐标 <dependency> <groupId>com.ibeetl</groupId> <artifactId ...

  10. 清北学堂模拟赛d7t6 拯救世界

    分析:如果题目中没有环的话就是一道裸的最长路的题目,一旦有环每个城市就会被救多次火了.把有向有环图变成有向无环图只需要tarjan一边就可以了. #include <bits/stdc++.h& ...