c++ 封装构造函数析构函数 C++语法详解之封装、构造函数、析构函数
人气:0大家先了解下什么是构造函数,什么是析构函数,作用是什么?
构造函数(方法)是对象创建完成后第一个被对象自动调用的方法。它存在于每个声明的类中,是一个特殊的成员方法。作用是执行一些初始化的任务。Php中使用__construct()声明构造方法,并且只能声明一个。
析构函数(方法)作用和构造方法正好相反,是对象被销毁之前最后一个被对象自动调用的方法。是PHP5中新添加的内容作用是用于实现在销毁一个对象之前执行一些特定的操作,诸如关闭文件和释放内存等。
下面在通过具体例子看下C++语法详解之封装、构造函数、析构函数。
成员变量私有化,提供公共的getter和setter给外界去访问成员变量
class Person { int age; public: void setAge(int age){ this->age = age; } int getAge(){ return this->age; } }; int main(){ Person person; person.setAge(10); cout << person.getAge() << endl; }
堆空间
在程序运行过程,为了能够自由控制内存的生命周期、大小,会经常使用堆空间的内存
堆空间的申请\释放
malloc \ free
new \ delete
new [] \ delete []
注意
- 申请堆空间成功后,会返回那一段内存空间的地址
- 申请和释放必须是1对1的关系,不然可能会存在内存泄露
现在的很多高级编程语言不需要开发人员去管理内存(比如Java),屏蔽了很多内存细节,利弊同时存在
- 利:提高开发效率,避免内存使用不当或泄露
- 弊:不利于开发人员了解本质,永远停留在API调用和表层语法糖,对性能优化无从下手
例如开盘int类型的空间,使用完之后销毁
int *p = (int *)malloc(sizeof(int)); *p = 10; free(p); int *p2 = new int; *p2 = 20; delete p2; int *p3 = new int[3]; *p = 10; *(p+1) = 20; *(p+2) = 30; delete [] (p3);
堆空间的初始化
memset
memset 函数是将较大的数据结构(比如对象、数组等)内存清零的比较快的方法
如下所示
Person person; person.age = 10; person.height = 199; //从person的地址开始,每个字节都赋值为0 memset(&person, 0, sizeof(person));
初始化
int *p1 = (int *)malloc(sizeof(int)); //*p1 未初始化 int *p2 = (int *)malloc(sizeof(int)); memset(p2, 0, sizeof(int));//将 *p2 的每一个字节都初始化为0
如下几种方式
int *p1 = new int; //未初始化 int *p2 = new int(); //被初始化为0 int *p3 = new int(5); //被初始化为5 int *p4 = new int[3]; //数组元素未被初始化 int *p5 = new int[3](); //3个数组元素都被初始化0 int *p6 = new int[3]{}; //3个数组元素都被初始化0 int *p7 = new int[3]{5}; //数组首元素被初始化为5,其他元素被初始化为0
构造函数(Constructor)
构造函数(也叫构造器),在对象创建的时候自动调用,一般用于完成对象的初始化工作
特点
- 函数名与类同名,无返回值(void都不能写),可以有参数,可以重载,可以有多个构造函数
- 一旦自定义了构造函数,必须用其中一个自定义的构造函数来初始化对象
注意
通过malloc分配的对象不会调用构造函数
一个广为流传的、很多教程\书籍都推崇的错误结论:
默认情况下,编译器会为每一个类生成空的无参的构造函数
正确理解:在某些特定的情况下,编译器才会为类生成空的无参的构造函数
比如我们自己写2个构造函数
class Person{ public: int age; Person(){ cout << "Person()" << endl; } Person(int age){ cout << "Person(int age))" << endl; } };
在不同的空间调用的时候,如下区别
// 全局区 Person p1; //调用Person() Person p2(); //这是一个函数,函数名是p2,返回值类型是Person,无参 Person p3(18); //调用 Person(int) int main(){ //栈空间 Person p4; //调用Person() Person p5(); //这是一个函数,函数名是p5,返回值类型是Person,无参 Person p6(18); //调用 Person(int) //堆空间 Person *p7 = new Person; //调用Person() Person *p8 = new Person(); //调用Person() Person *p9 = new Person(20); //调用 Person(int) }
析构函数
析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作
特点
函数名以~开头,与类同名,无返回值(void都不能写),无参,不可以重载,有且只有一个析构函数
注意
- 通过malloc分配的对象free的时候不会调用析构函数
- 构造函数、析构函数要声明为public,才能被外界正常使用
例如下面的代码
class Cat{ public: int age; Cat(){ cout << "Cat()" << endl; } ~Cat(){ cout << "~Cat()" << endl; } }; class Person{ public: int age; Cat *cat; Person(){ this->cat = new Cat(); cout << "Person()" << endl; } ~Person(){ cout << "~Person()" << endl; } }; int main(){ { Person person; } return 0; }
输出
Cat()
Person()
~Person()
当person销毁的时候,其持有的cat并没有销毁。
原因
当person销毁的时候,其指向cat对象的指针销毁了,但是堆空间的cat对象依然存在,就会有内存泄露。所以需要在析构函数里面来释放掉。类似的析构函数在许多其他语言底层也是应用广泛,例如Objective-C的源码中,大量使用析构函数。
代码改成如下所示:
~Person(){ delete cat; cout << "~Person()" << endl; }
输出
Cat()
Person()
~Cat()
~Person()
可知,cat对象才真正销毁。
总结
加载全部内容