C++语法详解之封装、构造函数、析构函数

大家先了解下什么是构造函数,什么是析构函数,作用是什么?

构造函数(方法)是对象创建完成后第一个被对象自动调用的方法。它存在于每个声明的类中,是一个特殊的成员方法。作用是执行一些初始化的任务。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对象才真正销毁。

总结

到此这篇关于C++语法详解之封装、构造函数、析构函数的文章就介绍到这了,更多相关c++ 封装构造函数析构函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++构造函数和析构函数的使用与讲解

    构造函数(constructor) 1.构造函数是种特殊的类成员函数,遵循如下规则: a.函数名与类名必须相同. b.没有返回值 例如: class Obj { ... public: Obj() { ... } }; 2.构造函数可以带参数,也可以重载 class Obj { ... public: Obj() { ... } Obj(int x, int y) { ... } }; 3.构造函数和普通成员函数不一样,一般不显示调用.在创建一个对象时,构造函数自动调用(编译器来完成). 析构函

  • C++类成员构造函数和析构函数顺序示例详细讲解

    对象并不是突然建立起来的,创建对象必须时必须同时创建父类以及包含于其中的对象.C++遵循如下的创建顺序: (1)如果某个类具体基类,执行基类的默认构造函数. (2)类的非静态数据成员,按照声明的顺序创建. (3)执行该类的构造函数. 即构造类时,会先构造其父类,然后创建类成员,最后调用本身的构造函数. 下面看一个例子吧 复制代码 代码如下: class c{public:    c(){ printf("c\n"); }protected:private:}; class b {pub

  • 深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结

    1 . 用同一个类的源对象构造一个目标对象时,会调用拷贝构造函数来构造目标对象,如果没有定义拷贝构造函数,将调用类的默认拷贝函数来构造目标对象.2 . 当一个函数的返回值为一个类的对象时,如果在调用函数中,没有定义一个对象来接收这个返回对象值,会用返回一个临时对象保存返回对象的值.在被调用函数结束时,这个临时对象被销毁.而当调用函数中有一个接受对象时,就将返回对象赋值给接收对象,这个返回对象在调用函数结束时调用析构函数.3. 当类有一个带有一个参数的构造函数时,可以用这个参数同类型的数据初始化这

  • 深入解析C++中的构造函数和析构函数

    构造函数:在类实例化对象时自动执行,对类中的数据进行初始化.构造函数可以从载,可以有多个,但是只能有一个缺省构造函数. 析构函数:在撤销对象占用的内存之前,进行一些操作的函数.析构函数不能被重载,只能有一个. 调用构造函数和析构函数的顺序:先构造的后析构,后构造的先折构.它相当于一个栈,先进后出. 复制代码 代码如下: #include<iostream>#include<string>using namespace std;class Student{ public:  Stud

  • C++中构造函数与析构函数的调用顺序详解

    前言 在使用构造函数和析构函数时,需要特别注意对它们的调用时间和调用顺序.在一般情况下,调用析构函数的次序正好与调用构造函数的次序相反:最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用. 简单来说,其构造函数的顺序就一句话: 基类构造函数 -> 成员的构造函数 -> 构造函数体内语句 看下面一个代码示例: #include <iostream> using namespace std; class A { publ

  • 详解C++ 编写String 的构造函数、拷贝构造函数、析构函数和赋值函数

    详解C++ 编写String 的构造函数.拷贝构造函数.析构函数和赋值函数 编写类String 的构造函数.析构函数和赋值函数,已知类String 的原型为: class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &other); // 拷贝构造函数 ~ String(void); // 析构函数 String & operate =(const String &ot

  • C++语法详解之封装、构造函数、析构函数

    大家先了解下什么是构造函数,什么是析构函数,作用是什么? 构造函数(方法)是对象创建完成后第一个被对象自动调用的方法.它存在于每个声明的类中,是一个特殊的成员方法.作用是执行一些初始化的任务.Php中使用__construct()声明构造方法,并且只能声明一个. 析构函数(方法)作用和构造方法正好相反,是对象被销毁之前最后一个被对象自动调用的方法.是PHP5中新添加的内容作用是用于实现在销毁一个对象之前执行一些特定的操作,诸如关闭文件和释放内存等. 下面在通过具体例子看下C++语法详解之封装.构

  • Android Kotlin开发实例(Hello World!)及语法详解

    Android Kotlin开发实例及语法详解 前言 Kotlin是一种在 Java虚拟机上执行的静态型别编程语言,它主要是由俄罗斯圣彼得堡的JetBrains开发团队所发展出来的编程语言.该语言有几个优势 1. 简洁 它大大减少你需要写的样板代码的数量. 2. 安全 避免空指针异常等整个类的错误. 3. 通用 构建服务器端程序.Android 应用程序或者在浏览器中运行的前端程序. 4. 互操作性 通过 100% Java 互操作性,利用 JVM 既有框架和库. 配置 在我们的AndroidS

  • 详解C++ 拷贝构造函数

    拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象.拷贝构造函数通常用于: 通过使用另一个同类型的对象来初始化新创建的对象. 复制对象把它作为参数传递给函数. 复制对象,并从函数返回这个对象. 如果在类中没有定义拷贝构造函数,编译器会自行定义一个.如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数.拷贝构造函数的最常见形式如下: classname (const classname &obj) { // 构造函数的主体 } 在这里,o

  • Python入门之基础语法详解

    一.我的经历及目标 在学习python之前:我学习过C/C++,在学校期间做过很多的项目,已经有两年多了,算是对C/C++非常的熟悉了,精通不敢说,但是对于面向过程和面向对象有很深刻的认识,做过很多的开发,学习数据库,MFC, QT, linux下利用C/C++进行服务器的开发,QT环境下进行模拟QQ的开发- 听说python挺火的,我也来尝试一门新的语言,python和c有80%的相似性,毕竟是用C来开发的语言,但是是面向过程的一门语言,有C++的继承等相似的特性,感觉更有信心学会它了,毕竟可

  • C语言类的基本语法详解

    目录 1.由C语言的结构体进入到C++中的类 2.C++中如何定义类? 3.C++中实例化一个对象 4.C++类的访问限定及其封装 C++中的访问限定符 5.C++中类的作用域 6.成员变量和方法在类中是如何存储的? 总结 1.由C语言的结构体进入到C++中的类 我们在C语言中当需要定义多个变量的数据集合时,第一时间会想到使用结构体来进行定义,例如我们定义一个学生变量,包含姓名.年龄.性别等信息,代码示例如下: struct Student{ char name[12]; int age; ch

  • DOS批处理中%~dp0等扩充变量语法详解

    有时候我们看到别人使用%~dp0 ~是扩展的意思,相当于把一个相对路径转换绝对路径 %0代指批处理文件自身 %1表示批处理文件命令行接收到的第一个参数,%2表示第二个,以此类推 %~d0 是指批处理所在的盘符,其中d代表drive %~p0 是指批处理所在的目录,其中p代表path %~dp0 是批处理所在的盘符加路径 cd %~dp0 就是进入批处理所在目录了 详细解释还可参考命令 call /? DOS批处理中%~dp0表示什么意思 (注: %0 就是该 batch 文件的文件名) 这句的意

  • 基于JS脚本语言的基础语法详解

    JS脚本语言的基础语法:输出语法  alert("警告!");  confirm("确定吗?");   prompt("请输入密码");为弱类型语言: 开始时要嵌入JS代码:<script type="text/javascript"></script>: 关于写程序是需注意的基本语法: 1.所有的字符全都是英文半角的: 2.大部分情况下每条语句结束后要加分号: 3.每一块代码结束后加换行:4.程序前呼

  • kotlin 官方学习教程之基础语法详解

    kotlin 官方学习教程之基础语法详解 Google 在今天的举行了 I/O 大会,大会主要主要展示内有容 Android O(Android 8.0)系统.Google Assistant 语音助手.Google 智能音箱.人工智能.机器学习.虚拟现实等.作为一个 Android 开发者,我关心的当然是 Android O(Android 8.0)系统了,那么关于 Android O 系统的一个重要消息是全面支持 Kotlin 编程语言,使得 Kotlin 成为了 Android 开发的官方

  • 对Golang import 导入包语法详解

    package 的导入语法 写 Go 代码的时经常用到 import 这个命令用来导入包,参考如下: import( "fmt" ) 然后在代码里面可以通过如下的方式调用: fmt.Println( "我爱北京天安门" ) fmt 是 Go 的标准库,它其实是去 GOROOT 下去加载该模块,当然 Go 的 import 还支持如下两种方式来加载自己写的模块: 相对路径 import "./model" // 当前文件同一目录的 model 目录

  • laravel高级的Join语法详解以及使用Join多个条件

    在laravel中我们常常会使用join,leftjion和rightjoin进行连表查询,非常的方便,但是我今天遇到一个问题,就是链表查询需要on多个条件,即我要订单的id和发货人都一样,默认的join只支持单个查询,所以我下面总结两种方法: 一.使用原是表达式(不推荐) 原生SQL中我们可以通过如下方法进行 select * from `orders` left join `users` on `orders`.`usename`=`users`.`usename` and `orders`

随机推荐