




已阅读5页,还剩21页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
精品文档类和对象初步1. 类的定义 在定义外成员函数的实现2. 类的成员函数之间可以相互调用,类的成员函数也可以重载,也可设默认参数值3. 一般来讲,一个对象占用的内存空间的大小等于其成员变量的体积之和。每个对象都有自己的存储空间(成员变量),但成员函数只有一份 对象名.成员名 指针-成员名 引用名.成员名4. private:一个类的私有成员,只能在该类的成员函数中才能访问 public: proteced: 5. class 默认 private struct默认public6. 内联成员函数:成员函数名前加inline 或函数体写在类定义内部的成员函数。执行更快,但会带来额外的内存开销构造函数1. 构造函数全局变量在堆上,系统自动初始化为零。局部变量在栈上,初始值是随机的,需要初始化。2. 构造函数:对对象进行初始化。构造函数执行时对象的内存空间已经分配,构造函数的作用是初始化这片空间。可重载,不写的话有默认构造函数,但是如果编写了构造函数,那默认构造函数不会再执行。是一类特殊的成员函数。不写返回值类型,函数名为类名。3. 对象在生成时一定会调用某个构造函数,一旦生成,不再执行构造函数。4. P183 Ctest *pArray3=new Ctest(4),new Ctest(1,2)5. 复制构造函数:其是构造函数的一种,只有一个参数,为本类的引用,防止混淆,构造函数不能以本类的对象作为唯一的参数。 默认复制构造函数。6. 复制构造函数被调用的三种情形:1用一个对象去初始化另一个对象时Complex C1(C2) Complex C2=C1; 2 函数的参数是类A的对象。形参未必等于实参 函数中用对象的引用不会调用复制构造函数 void Function(const Complex &c)3 函数的返回值是类A的对象7. 类型转换构造函数:除复制构造函数外,只有一个参数的构造函数 C=68. 析构函数:在对象消亡时调用,可以定义其做善后工作。是一类特殊的成员函数,一个类有且只有一个构造函数。默认析构函数9. 注意:函数的参数对象以及作为函数返回值的对象,在消亡时也会调用析构函数10. 构造函数 析构函数 变量的生存期: 全局变量在main函数开始执行前初始化。函数调用结束后静态局部对象不消亡。main函数结束时,静态局部对象先消亡,全局对象再消亡11. 静态成员变量和静态成员函数:实质是全局变量和全局函数,被所有的同类共享。生成在对象生成之前。计算体积时不会将静态成员变量算入其中 老师的coeblocks C0 13 静态成员变量必须在类定义外进行声明,声明的同时也可初始化。因为静态成员函数内部不作用于某个对象,所以不能访问非静态成员12. 常量对象和常量成员函数:常量对象一旦初始化后,值再也不能改变。常量对象和普通对象都可调用常量成员函数。通过常量对象调用常量成员函数。常量成员函数内不能调用同类的非常量成员函数,静态成员函数除外。13. 封闭类:包含成员对象的类。在定义封闭类的构造函数时,用初始化列表的方式初始化。封闭类对象生成时,先执行所有成员对象友元和this1. 友元函数:把全局函数和其它类的成员函数声明为友元函数后,可直接在友元函数内部访问该类的私有成员;但不能把其它类的私有成员函数声明为友元。2. 全局函数声明为友元:friend 返回值类型 函数名(参数表); 3. 其它类的成员函数声明为友元:friend 返回值类型 其它类的类名:成员函数名(参数表);4. 友元类:类A将类B声明为自己的友元,则类B中所有的成员函数都可访问类A对象中的私有成员。私有成员函数也可访问。5. 注意:友元关系不能传递。6. this指针:非静态成员函数的实际形参比编写的多一个,就是this指针,指向成员函数作用的对象。通过this指针找到对象所在的地址,继而找到对象非静态成员变量的地址。7. 注意:因为静态成员函数不作用于某个对象,所以在其内部无this指针,不能使用。运算符重载1. 运算符重载:是对已有的运算符赋予多重含义,使不同的运算符作用于不同的类型的数据时导致的不同的行为。 实质是编写运算符作为名称的函数。2. 返回值类型 operator 运算符(形参表).3. 使用了被重载的运算的表达式,会被编译成对运算符函数的调用,实参是运算符的操作数,运算的结果是函数的返回值。运算符可多次被重载,可重载为全局函数和成员函数。重载为全局函数时,参数个数等于操作符的个数;重载为成员函数时,参数的个数等于操作数的个数减1. ab被重载为a.operator-(b);4. 类名(构造函数参数表)这个写法表示生成一个临时对象。该临时对象没有名字,生存期到包含它的语句执行完为止。5. C+规定 = 只能重载为成员函数.赋值运算符可以连用。6. const char *c_str() const return str); 两种错误的情形: char *p=s.c_str(); strcpy(s.c_str(),tianggong 1);7. a=b=hello;等价于a.operator=(b.operator=(hello);8. (a=b)=c;等价于(a.operator=(b).operator=(c);9. 深复制和浅复制:两个对象的指针成员变量指向同一个地方,指向两个不同的地方。10. 将运算符重载为友元函数11. 重载插入运算符和流提取运算符:cout是ostream类的对象。ostream类和cout都是在iostream头文件中声明的。ostream类将多次重载为成员函数。比如:ostream & ostream:operator( const char*s) . return *this;) ostream & ostream:operator(int n) . return *this;) 12. 返回值*this是cout的引用 coutstar war5;等价于(cout.operator(star war).operatorCStudent:PrintInfo();4. 复合关系和继承关系:复合关系,有,表现为封闭类,但不一定只是封闭类。即一个类以另一个类的对象作为成员变量。 继承关系 ,是,类B继承类A,满足B所代表的事物也是A所代表的事物5. 类A知道类B:类A的成员变量是类B的指针6. /导出类构造函数和析构函数的构建基类的构造函数和析构函数不能被派生类继承。如果基类没有定义构造函数,派生类也可以不定义构造函数,全都采用缺省的构造函数,此时,派生类新增成员的初始化工作可用其他公有函数来完成。如果基类定义了带有形参表的构造函数,派生类就必须定义构造函数,提供一个将参数传递给基类构造函数的途径,以便保证在基类进行初始化时能获得必需的数据。如果派生类的基类也是派生类,则每个派生类只需负责其直接基类的构造,不负责自己的间接基类的构造。派生类是否要定义析构函数与所属的基类无关,如果派生类对象在撤销时需要做清理善后工作,就需要定义新的析构函数。多态与虚函数1. 多态:派生类对象的地址可以赋值给基类指针。对于通过基类指针调用基类和派生类中都有的同名的,同参数的虚函数的语句,编译时不需要确定执行的是基类的还是派生类的虚函数。当程序运行到该语句时,如果基类指针指向的是一个基类对象,则调用基类的虚函数;如果基类指向的是一个派生类对象,则调用派生类的虚函数。这种机制成为多态;2. 面向对象程序设计语言有封装,继承,多态三种机制,这三种机制能够有效提高程序的可读性,可扩充性和可重用性。3. 多态指同一事物可以完成不同的功能。分为编译时的多态和运行时的多态。前者主要指函数的重载(包括运算符重载),对重载函数的调用。后者主要与继承,虚函数等概念有关。4. 虚函数:声明前面加了virtual关键字的成员函数。virtual 关键字只能在类定义中的成员函数声明处使用,不能在类外编写成员函数体时使用。静态成员函数不能是虚函数。包含虚函数的类成为多态类。5. 多态可以简单地理解成同一条函数调用语句能调用不同的函数。或者对不同的对象发同一消息,使得不同对象有各自不同的行为。6. 注意:多态的语句调用的是哪个类的成员函数,是在运行时才能确定的,编译时不能确定。因此多态的函数调用语句是动态联编的,普通的函数调用语句时静态联编的。7. 通过基类引用实现多态。通过基类的引用调用虚函数的语句是多态的,即通过基类的引用调用基类和派生类中的同名同参表的虚函数时引用的是哪个类的对象,调用该对象的虚函数。8. 多态的实现原理:每一个有虚函数的类,都有一个虚函数表,列出了该类所有虚函数的地址。该类的任何对象都存放着该虚函数表的指针。位于对象存储空间的最前端,在数据成员之前,里面存放着虚函数表的地址。9. 多态的实现过程:根据基类指针所指向的或基类引用所引用的对象中存放的虚函数表的地址,查找要调用的虚函数的地址,调用虚函数。10. 类的成员函数可以相互调用,在成员函数(静态,构造,析构除外)中调用同类的虚函数的语句是多态的。11. 在构造函数和析构函数中调用虚函数不是多态的,即编译时即可确定。如果本类有该函数,则调用本类的,本类没有调用直接基类的,基类没有,调用间接基类的。12. 注意:只要在基类中某个函数被声明为虚函数,则在直接和间接派生类中,同名同参数的成员函数即使不写virtual也自动成为虚函数。13. 虚析构函数:如果一个基类指针指向new出来派生类的对象,释放该对象时是通过该基类指针来完成的。14. 如果基类的析构函数是虚函数,派生类的析构函数即使不用virtual关键字也自动成为虚函数。15. 注意:!析构函数可以是虚函数,但构造函数不可以!16. 纯虚函数:没有函数体的虚函数;在函数声明后加=0;17. 抽象类:包含纯虚函数的类;不能生成独立的对象,但抽象类可以作为基类,派生出新类。因此,独立的抽象类的对象不存在,但是被包含在派生类对象中的抽象类的对象,是可以存在的(但要实例化,有函数体)。18. 可以定义抽象类的指针或引用,让他们指向或引用抽象类的派生类的对象,实现多态。19. 如果一个类从抽象类派生而来,那么当且仅当它对基类中所有纯虚函数都进行覆盖并都写出函数体(也是),它才能成为非抽象类。函数调用也会带来降低效率的问题,因为调用函数实际上将程序执行顺序转移到函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。 因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来讲,解决其效率问题更为重要。引入内联函数实际上就是为了解决这一问题。 优点:可以加快代码的执行速度,当程序中调用内联函数时,该函数直接嵌入到每个调用语句处,每次函数调用时都用相对应的一段代码代替。可见它是以目标代码的增加为代价来换取时间的节省 主要解决功能相对简单、规模不大但使用相当频繁的程序运行效率问题。 使用内联函数时,遵守以下规则: 1. 内联函数体内不能包含任何静态变量,不能使用循环语句、switch;不能递归。 2.内联函数的定义必须出现在第一次被调用之前。 3.如果函数返回类型为void,则不能有return 语句。二:指针 通过指针引用数组元素 int a10; int *p; p+是合法的,而a+是错误的。a是数组名,它是数组的首地址,是常量;指向函数的指针变量:存放函数入口地址,指向的是程序代码存储区。 1、函数调用可以通过函数名调用,也可以通过指向函数的指针变量调用。 2、(*p) ( )表示定义一个指向函数的指针变量,在程序中把哪个函数的地址赋给它,它就指向哪一个函数。 3、给函数指针变量赋值时,只需给出函数名而不必给出参数。 p = max 4、用函数指针变量调用函数时,只需将(*p)代替函数名,在(*p)之后的括弧中根据需要写实参。 c=(*p)(a,b) 5、对指向函数的指针变量不能运算const pointer一个指针涉及到两个变量,一个是指针本身,另一个是指向的变量1.指向常量的指针const放在指针类型前,在程序中不能通过指针来间接修改指针所指向的内存空间的值,但可以改变指向的空间int a = 10;const int b = 20;const int* pa = &a;const int* pb = &b;a = 100; / okb = 200; / error*pa = 100; / error*pb = 200; / errorpb = &a; / okpa = &b; / ok2.指针常量const放在”*”和指针名之间,不能改地址能改所指向的值。int b =28;int* const pb = &b;*pb = 100; / okpb+; / error在定义指针常量时,必须将其初始化。3.指向常量的指针常量const在上述两个地方都加。既不允许修改指针值,也不允许修改指针变量所指向的值const int a = 10;const int * const pa = &a;a = 100; / error*pa = 100; / errorpa +; / error三:引用标题引用与指针的区别引用是 C+ 语言引进的概念,在 C 语言中没有。1)、指针是变量,引用是别名 引用是别名,引用本身没有地址。 2)、指针可作数组元素、引用不可 例: int *pa5;/指针数组 int a5; int &rea5=a;/不可 3)、可以有空指针,不可有空引用 例: int *p=null;/合法 int &re=null;/无意义四:类(class)私有(private)的数据和函数,只允许本类的成员函数访问或调用;保护(protected:)的数据和函数,允许本类和本类派生类的成员函数访问或调用;公有(public:)的数据和函数,允许本类和其它类的函数访问或调用。静态数据成员: 1.类的静态数据成员为该类的所有对象所共享。 2. 必须在类外文件作用域中的某个地方对静态数据成员赋初值(因为构造函数多次被调用,而静态数据成员只初始化1次): : = Const 成员函数中确保不会修改任何本类对象的数据成员。class constfunprivate:int a;public:void nonconstFunc( )a=18; /okvoid Func( ) consta=18 /errorthis指针:this指针是指向对象的指针,隐含在类的成员函数中,用来指向成员函数所属类的正在被操作对象。this指针可以看作是类自身的一个引用。构造函数的调用顺序 对于构造函数,先执行基类的,再执行对象成员的,最后执行派生类的。 对于析构函数,先执行派生类的,再执行对象成员的,最后执行基类的。导出类构造函数和析构函数的构建基类的构造函数和析构函数不能被派生类继承。如果基类没有定义构造函数,派生类也可以不定义构造函数,全都采用缺省的构造函数,此时,派生类新增成员的初始化工作可用其他公有函数来完成。如果基类定义了带有形参表的构造函数,派生类就必须定义构造函数,提供一个将参数传递给基类构造函数的途径,以便保证在基类进行初始化时能获得必需的数据。如果派生类的基类也是派生类,则每个派生类只需负责其直接基类的构造,不负责自己的间接基类的构造。派生类是否要定义析构函数与所属的基类无关,如果派生类对象在撤销时需要做清理善后工作,就需要定义新的析构函数。五:多重继承解决二义性问题解决方法一:用类名来限定(主要解决方法) 为避免二义性,可在调用时加上基类的名称,如 A:print() 或 B:print() 。解决方法二:同名覆盖在C 中声明一个同名成员函数print(),f()再根据需要调用 A: print() 或 B: print()解决方法三:使用虚函数面向对象设计的三大机制: 数据封装、继承、多态。继承:研究的是类与类之间的层次关系。多态性:指不同的对象接收到相同的消息时产生不同的响应动作,即对相同的函数名,却执行不同的函数体。函数重载和运算符重载实现类的一种多态性。静态联编和动态联编 联编(binding):是将函数调用与相应的函数体代码彼此关联的过程。 静态联编(static binding):如果联编过程在程序开始运行前的编译阶段完成。 例如:重载函数: void fun(int a,int b) void fun(float x,float y) void fun(char c) 函数名字相同,但各自参数不同,编译器能根据函数参数的类型和个数自动选择相应的函数体编译。动态联编(dynamic binding) 在程序运行时进行的联编方式。 例如:虚函数 C+中的虚函数,由于其函数名、返回值、函数参数完全相同,但函数体不同,因此编译阶段无法确定函数调用与哪个函数体关联,只能由系统在程序运行时确定。六:虚函数虚函数(virtual function)-运行时多态在定义某一基类(或其派生类)时,若将其中的某一函数成员的属性说明为virtual,则称该函数为虚函数。若基类中某函数被说明为虚函数,则意味着其派生类中也要用到与该函数同名、同参数表、同返回类型、但函数体不同。虚函数存在继承环境中。虚函数成员的定义语法:virtual 函数类型函数名(形参表)函数体程序举例 class BaseClasspublic:virtual void show() coutBase classendl;/如果不加关键字virtual,运行的结果都是Base class;;class Derived1:public BaseClasspublic:void show() coutDerived class1endl;class Derived2:public BaseClasspublic:void show() coutDerived class2show();p=&obj1;p-show();p=&obj2;p-show();return 0;通过虚函数,达到了用基类指针访问派生类对象成员函数的目的,这样,只要声明了基类指针,就可以使不同的派生类对象产生不同的函数调用,实现了程序的运行时多态。运行多态应该使用虚函数,并通过指针、引用或者成员函数调用虚函数纯虚函数和抽象类纯虚函数(pure virtual function): 在基类中声明虚拟函数而不给出具体的定义,把它的定义放在各个导出类中,此种函数为纯虚函数 通过基类指针或引用可以调用所有派生类的虚函数。抽象类:(abstract class) 声明了虚函数的类,基类只用于继承,仅作为一个接口,具体的功能则在派生类中实现。 注意:从抽象类可以派生出具体的或抽象类,但不能从具体类派生出抽象类。虚基类 虚基类的引入 用于有共同基类的场合 声明 以virtual修饰说明基类例:class B1:virtual public B 作用 主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题. 为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝类模板 C+中实现多态的另一种方法是类模板 类模板可以使用户为类定义一种模式,使得类中的一些数据成员和成员函数的参数,以及成员函数的返回值能够娶任意类型。#include template class TestClass public:T buffer10; /T类型的数据成员buffer数组大小固定为10 (灵活性差!) T getData(int j); /获取T类型buffer(数组)的第j个分量 ;template T TestClass:getData(int j) return *(buffer+j); ; void main() TestClass ClassInstA; /char取代T,从而实例化为一个具体的类 char cArr6=abcde;for(int i=0; i5; i+)ClassInstA.bufferi=cArri;for(i=0; i5; i+) char res=ClassInstA.getData(i);coutres ;coutendl; 程序执行后的显示结果如下:a b c d e2.1 13.2 24.3 35.4 46.5 57.6 既使用类型参数又使用 普通参数的类模板示例#include #include string.htemplate class TestClass public:T bufferi; /T类型的buffer,其大小随普通形参i的值变化(灵活性大!)T getData(int j); ;template T TestClass:getData(int j) return *(buffer+j); ;TestClass ClassInstF;double fArr6=12.1, 23.2, 34.3, 45.4, 56.5, 67.6;for(i=0; i6; i+)ClassInstF.bufferi=fArri-10;for(i=0; i6; i+) double res=ClassInstF.getData(i);coutres ;coutendl;常量指针与指针常量1.指向常量的指针const放在指针类型前,在程序中不能通过指针来间接修改指针所指向的内存空间的值,但可以改变指向的空间int a = 10;const int b = 20;const int* pa = &a;const int* pb = &b;a = 100; / okb = 200; / error*pa = 100; / error*pb = 200; / errorpb = &a; / okpa = &b; / ok2.指针常量const放在”*”和指针名之间,不能改地址能改所指向的值。int b =28;int* const pb = &b;*pb = 100; / okpb+; / error在定义指针常量时,必须将其初始化。3.指向常量的指针常量const在上述两个地方都加。既不允许修改指针值,也不允许修改指针变量所指向的值const int a = 10;const int * const pa = &a;内存模型描述的是程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节.不同平台间的处理器架构将直接影响内存模型的结构.首先介绍一下C+中有继承关系的类对象内存的布局:在C+中,如果类中有虚函数,那么它就会有一个虚函数表的指针_vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。之后是子类自己的成员变量数据。对于子类的子类,也是同样的原理。但是无论继承了多少个子类,对象中始终只有一个虚函数表指针。为了探讨C+类对象的内存布局,先来写几个类和函数首先写一个基类: 1. class Base 2. 3. public: 4. virtual void f() cout Base:f endl; 5. virtual void g() cout Base:g endl; 6. virtual void h() cout Base:h endl; 7. int base; 8. protected: 9. private: 10. ; 然后,我们多种不同的继承情况来研究子类的内存对象结构。1. 无虚函数集继承 1. /子类1,无虚函数重载 2. class Child1 : public Base 3. 4. public: 5. virtual void f1() cout Child1:f1 endl; 6. virtual void g1() cout Child1:g1 endl; 7. virtual void h1() cout Child1:h1 endl; 8. int child1; 9. protected: 10. private: 11. ; 这个子类Child1没有继承任何一个基类的虚函数,因此它的虚函数表如下图:我们可以看出,子类的虚函数表中,先存放基类的虚函数,在存放子类自己的虚函数。2. 有一个虚函数继承 1. /子类2,有1个虚函数重载 2. class Child2 : public Base 3. 4. public: 5. virtual void f() cout Child2:f endl; 6. virtual void g2() cout Child2:g2 endl; 7. virtual void h2() cout Child2:h2 endl; 8. int child2; 9. protected: 10. private: 11. ; 当子类重载了父类的虚函数,则编译器会将子类虚函数表中对应的父类的虚函数替换成子类的函数。3. 全部虚函数都继承 1. /子类3,全部虚函数重载 2. class Child3 : public Base 3. 4. public: 5. virtual void f() cout Child3:f endl; 6. virtual void g() cout Child3:g endl; 7. virtual void h() cout Child3:h 参考数据结构,这里我们就不再一一讨论了。2.生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。3.分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。4.分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C+函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。明确区分堆与栈:在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。首先,我们举一个例子: 1. void f() 2. 3. int* p=new int5; 4. 这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下: 1. 00401028 push 14h 2. 0040102A call operator new (00401060) 3. 0040102F add esp,4 4. 00401032 mov dword ptr ebp-8,eax 5. 00401035 mov eax,dword ptr ebp-8 6. 00401038 mov dword ptr ebp-4,eax 这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。好了,我们回到我们的主题:堆和栈究竟有什么区别?主要的区别由以下几点: 管理方式不同; 空间大小不同; 能否产生碎片不同; 生长方向不同; 分配方式不同; 分配效率不同;管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:打开工程,依次操作菜单如下:Project-Setting-Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。static用来控制变量的存储方式和可见性函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此 函数控制)。需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。static的内部机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年护士中级面试技巧及护理实操模拟题答案全攻略
- 2025年化工工艺专业基础与炼油装置操作实践模拟题集
- 2025年仓库安全员招聘面试题库从基础到进阶
- 2025年炼油装置中级操作工面试题集与答案解析
- 2025年水资源保护与生态流量管理实战手册与考试题库及答案
- 2025年销售代表初级面试模拟题及答案全收录
- 电剪安全知识培训课件
- 2025年财务管理主管竞聘面试题集与答案
- 2025年仓库设备维护与操作笔试模拟题及答案解析
- 2025年烹饪技艺初级考核试题集
- 2025年四川省建筑施工企业安管人员考试(企业主要负责人·A类)历年参考题库含答案详解(5卷)
- 实战能力评估模型-洞察及研究
- 超声引导髂筋膜阻滞技术
- 以童心为笔:基于儿童心理发展需求的小学校园公共活动空间设计
- 铁路建设工程质量安全监督管理办法
- 数字经济与市场结构-洞察及研究
- DB42T 1496-2019 公路边坡监测技术规程
- 学校餐厅试吃活动方案
- 山水项目管护方案(3篇)
- 医院直播策划活动方案
- 2025至2030全球及中国正念冥想应用行业产业运行态势及投资规划深度研究报告
评论
0/150
提交评论