析构函数

malloc和new的比较

你。 提交于 2019-11-30 05:44:53
摘要:本文主要分析了malloc和new两者的区别。 1、申请的内存所处的位置 malloc是c语言中的概念,申请的是堆中的内存空间。堆是计算机操作系统中特殊分配出来的一个内存区域,用于程序的内存动态分配。 new是c++中的概念,申请的空间称之为自由存储区。自由存储区是针对于new的一个概念,可以理解为凡是用new申请的空间,都可以称之为自由存储区。 注意:自由存储区不一定是堆,也有可能是静态存储区。 2、返回类型 new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。 malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。 3、内存分配失败的返回值 new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL; malloc分配内存失败时返回NULL。 4、是否需要指定申请内存的大小 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。 malloc则需要显式地指出所需内存的尺寸。 5、是否调用析构函数和构造函数 使用new操作符来分配对象内存时会经历三个步骤: 第一步:调用operator new 函数(对于数组是operator new[])分配一块足够大的,原始的,未命名的内存空间以便存储特定类型的对象。 第二步

c++笔记(中)

强颜欢笑 提交于 2019-11-30 04:40:17
继承与派生 面向对象程序设计4个主要特征:抽象,封装,继承,多态性 c++通过继承实现可重用性。有时两个类的内容基本相同或有一部分相同,这时可以利用原来声明的类作为基础,再加上新的内容即可,减少了工作量。 //比如有一个类class student { public: void display() {cout<<"num:"<num<<endl; cout<<"name"<<nam<<endl; cout<<"sex"<<sex<<endl; } private: int num; string nam; char sex; }; 现在想增加student 类的信息,可以重新写 class student1 { public: void display() {cout<<"num:"<num<<endl; cout<<"name"<<nam<<endl; cout<<"sex"<<sex<<endl; cout<<"age"<<age<<endl; cout<<"address"<<addr<<endl; } private: int num; string nam; char sex; int age; char addr{20}; }; 也可以通过继承来实现 class student1: public student //声明基类是student, { public:

C++:Special Member Functions

天大地大妈咪最大 提交于 2019-11-30 02:53:48
Special Member Functions 区别于定义类的行为的普通成员函数,类内有一类特殊的成员函数,它们负责类的 构造 、 拷贝 、 移动 、 销毁 。 构造函数 构造函数控制对象的初始化过程,具体来说,就是初始化对象的数据成员。构造函数的名字与类名相同,且没有返回值。构造函数也可以有 重载 ,重载区别于参数数量或参数类型。与其他成员函数不同的是,构造函数不能被声明为 const ,对象的常量属性是在构造函数完成初始化之后获得的。 默认构造函数 默认构造函数的工作是:如果在类内定义了成员的初始值,那么用初始值初始化成员;否则,默认初始化成员。 默认初始化是指定义变量时不赋予初始值时被赋予默认值的动作。定义于函数体外的内置类型如果没有被显式初始化,则赋值0;在函数体内定义的变量不会被初始化。 class LiF { public: LiF(int _lif = 0) { lif = _lif; } // 指定了lif的初值,这是一个默认构造函数 private: int lif; } LiF l; // 调用默认构造函数,此时l.lif值为0 再看下面这种情况: class LiF1 { public: LiF1(int _lif = 0) { lif = _lif; } int lif; }; class LiF2 { public: LiF1 lif1; }; LiF2

c# 类(2)

一世执手 提交于 2019-11-29 22:14:46
构造函数 和 析构函数 Constructors and destructors 构造函数是一个特殊的函数,当实例化一个类的时候自动调用这个函数,无返回值(不用定义返回类型) 普通函数的定义 public string Describe() 里面定义了 string 这个返回类型 而构造函数 public Car() 构造函数可以被重载 意味着我们可以写好几个构造函数,然后带有不同的参数个数或类型 这里就有两个构造函数,意味着我们在实例化 Car 这个类的时候,可以传参 也可以不传参 构造函数可以调用另外的构造函数 见 https://csharp.net-tutorials.com/classes/constructors-and-destructors/   用途暂时没想到,以后再说 析构函数 C#有自动的垃圾回收机制,不用手动来进行无用的资源释放与处理 析构函数是在构造函数前面加波浪线 ~Car() 一旦这个Car类的对象被回收以后,会自动调用这个析构函数 ​ 来源: https://www.cnblogs.com/springbrotherhpu/p/11537297.html

c/c++常见面试题(一)

佐手、 提交于 2019-11-29 21:39:57
0.static、const、volatile的作用和区别 static: https://www.cnblogs.com/Manual-Linux/p/8870038.html 第一 、在修饰变量的时候,static修饰的静态局部变量只执行一次,之后再初始化无效。而且延长了局部变量的生命周期,直到程序运行结束以后才释放。 第二 、static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以。 第三 、static修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候自动初始化为0 const: 1.修饰的变量只读,不可改变 2.防止意外修改,减少bug 3.可以节省空间,避免不必要的 内存分配 volatile: 告诉编译器这个变量随时可变,不需要优化 1.请问全局变量和局部变量能否重名 能,局部会屏蔽全局。要用全局变量,需要使用"::" 2. 用三目运算符(X)>(Y)?(X):(Y)宏定义实现比较两个数的大小 #define MAX(X, Y) ((X)>(Y)?(X):(Y)) 3.malloc的了解 malloc是动态内存分配,是用户动态申请系统分配指定字节的内存块的函数。返回类型是 void* 类型 对应free,

析构函数

时光总嘲笑我的痴心妄想 提交于 2019-11-29 19:31:49
配合构造函数使用,如果结构体/类没有用到堆的空间,可以不用析构函数,但是一旦有成员函数或者构造函数使用了堆上的空间,那就必须要使用析构函数。自己在成员函数中free堆的空间也可以,但是如果此成员函数释放了,别的成员函数又想要用怎么办?难道是再次申请?所以释放的时机是较难把握的,合理的释放时机就是在创建的对象完全不用的时候释放,所以C++提供了析构函数,用来最后释放堆上的内存。 ———————————————— 版权声明:本文为CSDN博主「雲烟」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/baidu_33879812/article/details/92114140 析构函数 和类名一样需要 ~ 符号。 一个类只能有一个析构。 类中没有提供构造,析构,会提供一个默认的什么都不做的 构造和析构 #include <iostream> #include <string> using namespace std; class CPerson { private: char* m_pszName; public: CPerson() { m_pszName = new char[10]; strcpy_s(m_pszName,10,"asdasdasd"); } ~CPerson() //

C++构造函数和析构函数调用虚函数时都不会使用动态联编

六眼飞鱼酱① 提交于 2019-11-29 17:11:05
可以,虚函数底层实现原理(但是最好不要在构造和析构函数中调用) 可以,但是没有动态绑定的效果,父类构造函数中调用的仍然是父类版本的函数,子类中调用的仍然是子类版本的函数。 effictive c++第九条,绝不在构造和析构过程中调用virtual,因为构造函数中的base的虚函数不会下降到derived上。而是直接调用base类的虚函数。绝不在构造和析构函数中调用virtual函数: a) 如果有继承,构造函数会先调用父类构造函数,而如果构造函数中有虚函数,此时子类还没有构造,所以此时的对象还是父类的,不会触发多态。更容易记的是基类构造期间,virtual函数不是virtual函数。 b) 析构函数也是一样,子类先进行析构,这时,如果有virtual函数的话,子类的内容已经被析构了,C++会视其父类,执行父类的virtual函数。 c) 总之,在构造和析构函数中,不要用虚函数。如果必须用,那么分离出一个Init函数和一个close函数,实现相关功能即可。 原文链接:https://blog.csdn.net/chen134225/article/details/81564972 第一个理由是概念上的。 在概念上,构造函数的工作是生成一个对象。在任何构造函数中,可能只是部分形成对象——我们只能知道基类已被初始化,但并不能知道哪个类是从这个基类继承来的。然而,虚函数在继承层次上是“向前

C++语法之构造、析构函数

我怕爱的太早我们不能终老 提交于 2019-11-29 16:56:47
C++语法之构造、析构函数 众所周知,在类的一个对象被创建时,编译系统就会自动为该对象分配空间。但在分配空间后还会自动调用一个函数,这个函数我们就称为构造函数。构造函数的作用是为对象的成员变量赋初值。 构造函数:构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)。创建对象时,根据对象的类型不停,调用不同的构造函数。当没有定义构造函数时系统就会生成隐式的构造函数,无任何实际作用。 例如: include using namespace std; class rec { public: rec(){cout<<"构造一个长方形甲\n";} rec(int l,int w){ length = l; width = w;cout << "长方形乙的面积为:" << length * width << endl;} rec(int l,int w,int h){ length=l ; width=w ; height=h ; cout<<"长方体丙的体积为:" <<length width height<<endl;} private: int length; int width; int height; }; void main() {//下面分别调用不同的构造函数 rec a; rec b(3,4); rec c(3,4

游戏开发面试总结2

风流意气都作罢 提交于 2019-11-29 15:04:29
总结一些面试常问的吧 1:聊一聊虚函数吧 C++中,虚函数主要是实现了多态机制,简而言之就是 用父类型的指针指向了子类型的实例,然后通过父类的指针去调用子类的成员函数。 每一个含有虚函数的类都至少有一个与之对应的虚函数表,存放着这个类所由虚函数对应的函数指针。 虚函数表在构建的过程中的步骤:    1:拷贝基类的虚函数表   2:替换重写的虚函数指针   3:追加子类的虚函数指针 这些步骤是编译器完成的 2: 虚析构函数:虚析构函数使得在删除指向子类对象的基类指针的时候可以调用子类的析构函数达到释放子类中堆内存的目的,防止内存泄漏 当delete父类的指针时,由于子类的析构函数和父类的析构函数形成多态,所以先调用子类的析构函数再调用父类的析构函数 。 纯虚函数:形式为virtual void fun() = 0; 不需要实现,因为不会被调用到 抽象基类:至少有一个纯虚函数的类,抽象基类不能产生改类的对象,但是可以有这个类的指针或者引用;子类中必须将纯虚函数实现,否则子类也是抽象基类 3: 聊一聊堆排序吧 堆排序分为两个步骤:   1:根据初始的输入数据,进行HeapAdjust形成初始堆     复杂度为O(n),包括比较和交换 公式可以写为s = 2^( i - 1 ) * ( k - i ),2^( i - 1) 表示该层上有多少个元素,( k - i)

C++多态原理与内部结构

陌路散爱 提交于 2019-11-29 14:59:05
多态类型 多态可以分为 静态多态 和 动态多态 : 静态多态其实就是重载 ,因为静态多态是指在编译时期在形成符号表的时候, 对函数名做了区分 ,根据参数列表来决定调用哪个函数, 也叫编译时多态 ; 动态多态是指通过子类重写父类的虚函数来实现 的,因为是 在运行期间决定调用的函数 ,所以称为 动态多态 ,一般情况下我们不区分这两个时所说的多态就是指动态多态。 动态多态的实现与虚函数表,虚函数指针相关,下面详述。 虚函数相关 首先我们来说一下,C++中多态的表象, 在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数 。如果对象类型是派生类,就调用派生类的函数,如果是基类,就调用基类的函数。 实际上, 当一个类中包含虚函数时,编译器会为该类生成一个虚函数表,保存该类中虚函数的地址 ,同样,派生类继承基类,派生类中自然一定有虚函数,所以 编译器也会为派生类生成自己的虚函数表 。当我们定义一个派生类对象时,编译器检测该类型有虚函数,所以为这个派生 类对象生成一个虚函数指针,指向该类型的虚函数表 ,这个虚函数 指针的初始化在构造函数中完成 的。后续如果有一个基类类型的指针,指向派生类,那么当调用虚函数时, 从对象的前4个字节中取虚表地址 ,根据所指真正对象的虚函数表指针去寻找虚函数的地址,也就可以调用派生类的虚函数表中的虚函数