东莞专业做网站的公司有哪些,前程无忧官网,wordpress加入海报功能,大型网页设计感谢大佬的光临各位#xff0c;希望和大家一起进步#xff0c;望得到你的三连#xff0c;互三支持#xff0c;一起进步 个人主页#xff1a;LaNzikinh-CSDN博客 文章目录 前言一.对象的动态建立和释放二.多个对象的构造和析构三.深拷贝与浅拷贝四.C类的内存管理总结 前言 … 感谢大佬的光临各位希望和大家一起进步望得到你的三连互三支持一起进步 个人主页LaNzikinh-CSDN博客 文章目录 前言一.对象的动态建立和释放二.多个对象的构造和析构三.深拷贝与浅拷贝四.C类的内存管理总结 前言
我们前面讲起了一些关于C中类与对象的一些语法构造函数C构函数初始化成员列表等等也讲了面对对象的程序设计方法和面对过程的程序设计方法有什么区别我们这次就主要针对类与对象的拷贝和一些存储内存的角度继续了解 一.对象的动态建立和释放 我们在C语言中动态开辟内存和释放内存用用到的就是malloc函数和free函数当然在C中也是可用的但是来到了C我们就要用C的语法在这个地方我们主要是用new和delete来动态建立和释放。 new和delete都是运算符不是库函数不需要单独添加头文件,而我们malloc和free都需要头文件而且是函数有函数的调用就要开辟栈空间所以而运算符是不需要的所以说这也体现的C的好处 格式 new 1、类型指针 指针变量名 new 类型 2、类型指针 指针变量名 new 类型(初始值) 3、类型指针 指针变量名 new 类型[元素个数] delete 1、delete 指针变量名 2、delete[] 指针变量名
int main()
{//在堆上申请一个int类型大小的空间并且将申请的空间初始化为10int* p1 new int(10);delete p1;//在堆上申请4个int类型大小的空间并没初始化int* p2 new int[4];delete[4] p2;//在堆上申请一个Box类型大小的空间,会构造对象出来Box* p3 new Box;delete p3;//在堆上申请4个Box类型大小的空间,会构造对象出来Box* p4 new Box[4];delete[4] p4;return 0;
}
注意
new和delete是运算符不是函数因此执行效率高。虽然为了与C语言兼容C仍保留malloc和free函数但建议用户不用malloc和free函数而用new和delete运算符。new/delete 和 malloc/free有何取别呢 1、malloc/free为C的标准库函数new、delete则为C的操作运算符 2、new能自动计算需要分配的内存空间而malloc需要手工计算字节数 3、new与delete直接带具体类型的指针malloc和free返回void类型的指针。 4、new类型是安全的而malloc不是。例如int*p new float2就会报错 而int p malloc2sizeofint编译时编译器就无法指出错误来。 5、new调用构造函数malloc不能delete调用析构函数而free不能 6.new/delete是操作符可以重载malloc/free则不能 二.多个对象的构造和析构 我们之前学了析构函数和构造函数但是有没有想过在多个对象中析构和构造的调用顺序是怎么样的呢 注意1.当类中的成员变量为另一个类的实例化对象时我们称这个对象为成员对象。2.成员变量虽属的类中没有实现无参的构造函数是需要使用初始化成员列表。
#includeiostream
using namespace std;
class ABC
{
public:ABC(int A, int B, int C){cout ABC(int A, int B, int C) endl;}~ABC(){cout ~ABC() endl;}
private:int a;int b;int c;
};
class myD
{
public:myD() :abc1(1, 2, 3), abc2(3, 5, 7){cout myD() endl;}~myD(){cout ~myD() endl;}private:ABC abc1;ABC abc2;
};
int main()
{myD a;return 0;
} 调用顺序 最开始先是构造成员对象所以先调用成员对象所对应的构造函数然后就是构造函数本身最后是析构函数析构函数的调用顺序与构造相反总之就是先构造成员对象在构造本身析构相反 三.深拷贝与浅拷贝
3.1拷贝构造函数 当使用已经构造好的对象t1初始化一个新的对象就会调用拷贝构造函数 //拷贝构造函数
Test(const Test t)
{cout Test(const Test t) endl;
}
3.2对象的赋值
思考这样的赋值对吗
#includeiostream
using namespace std;
class Test
{
public:int x;int y;int* sum;Test(int a, int b):x(a),y(b){sum new int[4];}//拷贝构造函数Test(const Test t){cout Test(const Test t) endl;x t.x;y t.y;sum t.sum;}~Test(){delete[4] sum;}
};
int main()
{Test t1(10,20);t1.sum[0] 10; t1.sum[1] 11; t1.sum[2] 12; t1.sum[3] 13;Test t2 t1;
} 答案是不对的不可以直接这样赋值会出现问题为什么呢因为他们的sum的地址都指向同一个地方。这个赋值并没有开辟两个空间而是让这两个成员变量都指向了同一个区域。调用析构函数的时候会释放两次因此就会造成问题 这个就是拷贝错误拷贝分为浅拷贝和深拷贝同一类对象之间的负值一般是没有副作用的但是类中有指针并且指针指向的动态分配的内存空间时会导致两个对象的指针指向同一块内存空间遇到这种情况时浅拷贝他就不能解决问题我们就要用深拷贝去解决 改
class Test
{
public:int x;int y;int* sum;Test(int a, int b):x(a),y(b){sum new int[4];}//拷贝构造函数Test(const Test t){cout Test(const Test t) endl;x t.x;y t.y;//浅拷贝//sum t.sum;//深拷贝sum new int[4];for (int i 0; i 4; i){sum[i] t.sum[i];}}~Test(){delete[4] sum;}
};
3.3浅拷贝 1、同一类型的对象之间可以赋值使得两个对象的成员变量的值相同两个对象仍然是独立的两个对象这种情况被称为浅拷贝 2、一般情况下浅拷贝没有任何副作用但是当类中有指针并且指针指向动态分配的内存空间将导致两个对象的指针变量向同一块内存空间当两个对象被销毁时调用析构函数因为在析构函数中会释放指针所指向的堆空间造成同一块堆空间被释放两次从而导致程序运行出错。 3、如果我们没有实现拷贝构造函数C编译器会自动实现一个拷贝构造函数我们称之为默认拷贝构造函数但是在默认拷贝构造函数中实现的时浅拷贝 3.4深拷贝 实现拷贝构造函数在拷贝构造函数中需要对对象中的指针变量进行单独的内存申请。两个对象中的指针变量不会指向同一块内存空间然后再将右值对象指针所指向的空间中的内容拷贝到新的对象指针所指向的堆空间中。 四.C类的内存管理 C类和对象中成员变量和成员函数是分开存储的成员变量静态成员变量存储于全局数据区中普通成员变量存储于函数中与结构体变量有相同的字节对其方式。成员函数存放于代码段 证明
#includeiostream
using namespace std;
class C1
{
public:int i;int j;int k;
};
class C2
{
public:int i;int j;int k;int getK(){return k;}void setK(int val){k val;}
};int main()
{C1 c1;C2 c2;cout sizeof(c1) endl;cout sizeof(c2) endl;
} 4.2this指针 this指针的本质--指针常量当形参和成员变量同名时可用this指针来区分 using namespace std;
class ABC
{
public:int x, y, z;ABC(int x, int y, int z){x x;y y;z z;}
};
int main()
{ABC a(1, 2, 3);return 0;
}
经过编译 this指针指向调用该成员函数的对象 class ABC
{
public:int x, y, z;ABC(ABC*const this,int x, int y, int z){this-x x;this-y y;this-z z;}
};
int main()
{//a就是this指针ABC a(a,1, 2, 3);return 0;
}
4.3类的静态成员变量 如果我要记录一个农场里面羊的数量我该如何写呢如果用C语言来写的话就是面对过程的编程只有有样出生我就有羊死去我就减减但是麻烦的是每个羊他可能会有年龄名字就会非常的繁琐但是如果你是用c面对对象的编程的话我就可以直接构造一个样的类利用构造函数和析构函数来完成这个事情而静态成员变量可以让这个事情完成的更完美他是什么意思呢可以用关键字static用于声明一个类的成员静态的成员提供了一个同类对象的共享机制 #includeiostream
using namespace std;
class sheep
{
public:int age;char name[32];sheep(){cnt;}~sheep(){cnt--;}static int cnt;
};int sheep::cnt 0;
int main()
{return 0;
} static int cnt;只是声明了一个静态成员变量不是内或者对象的成员变量但是他的作用与在内和这些类的所有实例化对象中 int sheep::cnt 0;定义了sheep这个类中的静态成员变量cnt并初始化为零如果不初始化默认为4 4.4类的静态成员函数
定义使用static修饰的成员函数叫做静态成员函数 在静态成员函数内不能访问除静态成员函数以外的其他成员变量 什么时候可以将函数设计成静态成员函数 函数的行为跟类的实例无关只跟类有关 静态成员函数的用处: 1.访问被private/protected修饰静态成员变量 2.可以实现某些特殊的设计模式:如Singleton(单例模式) 3.可以封装某些算法比如数学函数如Insintan等等这些函数本就没必要属于任何一个对象所以从类上调用感觉更好比如定义一个数学函数类Math。 总结
这次我们主要讲解了对象的动态开辟和释放对比C语言的不同和前面所讲到的析构和构造的一个升华是多对象的析构和构造还讲了C独特的浅拷贝和深拷贝以及C类的一些内存管理如类的静态成员变量静态成员函数和this指针