- 813.38 KB
- 2022-08-11 发布
- 1、本文档由用户上传,淘文库整理发布,可阅读全部内容。
- 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,请立即联系网站客服。
- 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细阅读内容确认后进行付费下载。
- 网站客服QQ:403074932
左值与右值见C++primer中文版39页变量的声明与定义的区别:见C++primer中文版45页\n变量的两种初始化形式:inta(10)和inta=10;关键字-register:这个关键字请求编译器尽可能地将变量存在CPU的内部寄存器中,而不是通过内存寻址访问提高效率。使用register的限制:register变量必须是能被CPU寄存器所接受的的类型。register变量必修是一个单值,并且长度小于等于整型的长度,而且寄存器变量可能不存放在内存中,所以不能使用取地址运算符&来获得寄存器register变量的地址。作用域操作符::作用域:变量在程序中的起作用范围简单分为:全局作用域、局部作用域、语句作用域作用域优先级:范围越小优先级越高作用域运算符:“::”如果希望在局部变量的作用域内使用同名的全局变量,可以在该变量前加上“::”,“::”称为作用域运算符 #includeintavar=10; //全局变量avarvoidmain(){ intavar=20; //局部变量avar cout<<"avaris:"<叫做类型参数表。Class也可以用typename代替。第4章类和对象4.1类及其实例化类成员包括数据成员和成员函数。不能在类体内给数据成员赋值,但是可以通过构造函数初始化或通过成员函数赋值。如果没有使用关键字,则所有成员默认声明为private权限。Java的默认访问权限叫做(无修饰,友好的friendly)只允许同一包中的类的方法访问。赋初值与初始化的区别:赋初值是在有了对象之后,使用成员函数给数据成员赋值。初始化是产生对象时就使对象的数据成员具有指定值。初始化使用构造函数实现。4.2构造函数一旦程序定义了自己的构造函数,系统就不再提供默认构造函数。如果程序员没有再定义一个无参数的构造函数,但又声明了一个没有初始化的对象,则因系统已经不再提供默认构造函数而造成编译错误(JAVA亦如此)。定义构造函数不能指定返回类型,即使是void类型也不可以。声明对象指针时只是在内存中创建了一个指针变量,只有new对象后赋值给该指针才能调用该对象的构造函数。#includeclassMyClass{public:MyClass(){cout<<1;}};voidmain(){MyClassa,b[2],*P;MyClass*p=newMyClass();\n}使用运算符new用于建立生存期可控的对象,new返回这个对象的指针。New建立一个动态对象时,new首先分配足以保存Point类的一个对象所需要的内存,然后自动调用构造函数来初始化这块内存,再返回这个动态对象的地址。使用new建立的动态对象只能用delete删除,以便释放所占空间。4.10.1编译指令所有的编译指令都是以#开始,每条指令独占一行,同一行不能有其他编译指令与C++语句。(注释除外)第5章特殊函数和成员5.1对象成员的初始化1.对象成员:具有某个类型的数据成员。2.对象成员的说明(P105)3.对象成员的初始化:A::A(参数表0):成员1(参数表1),成员2(参数表2),成员n(参数表n){其他操作}4.类组合的构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。(析构函数的调用顺序相反)。若调用缺省构造函数,则内嵌对象的初始化也将调用相应的缺省构造函数。见东南大学C++程序设计2005版第28讲。5.2静态成员1.全局变量与静态变量的区别(C程序设计第二版,谭浩强P172)从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。\n从变量值存在的时间(即生存期)角度来分,可以分为静态存储方式和动态存储方式。静态变量是局部变量的一种,叫做静态局部变量。使用静态变量的目的是消除全局变量。2.自动(auto)变量不能在类体外进行赋值(因为作用域的缘故)应该在构造函数里面赋值,静态变量可以在类体外进行赋值。(自考教材P107)#includeusingnamespacestd;classTest{staticintx;//静态变量inty;//自动变量voidtte(inta,inte){x=a,y=e;}//成员函数内赋值staticvoidsfunc(inta){y=a;}//errorC2597:illegalreferencetodatamember'Test::y'ina//staticmemberfunction静态成员函数(由于没有this指针)//不能访问非静态成员。staticvoidsfunc(Test&r,inta){r.y=a;}//只能通过对象名或指向对象的指针访问该对象的非//静态成员。};intTest::x=8;//可以编译通过intTest::y=1;//编译通不过voidmain(){cout<<"aa";}3.静态局部变量在编译时赋初值,即只赋初值一次,在程序运行时它已经有初值。以后每次调用函数时不再重新赋初值而是保留上次函数调用结束时的值。4.静态对象:使用static声明的类的对象。注意:构造函数在代码执行过程中,第一次遇到他的变量定义时被调用,但直到整个程序结束之前仅调用一次。析构函数在整个程序退出之前被调用,同样也只调用一次。5.类中任何成员函数都可以访问静态数据成员。静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员。5.4const对象一个const对象只能访问const成员函数,否则将产生编译错误。常数据成员仍保留静态成员特征,需要在类外初始化。第六章继承与派生6.1继承和派生的基本概念C++中有两种继承:单一继承和多重继承,java只支持单一继承。6.2单一继承1.声明继承的访问控制是指如何控制基类成员在派生类中的访问属性。包括(public,protected,private)。2.在派生类中继承的基类成员的初始化,需要由派生类的构造函数调用基类的构造函数来完成,这和初始化对象成员有类似之处。3.构造函数和析构函数是不被继承的,所以一个派生类只能调用它的直接基类的构造函数。4.类中成员的访问控制声明中protected声明类的保护成员对派生类的成员函数而言,它是公有成员,可以被访问;而对其他函数而言则仍是私有成员,不能被访问。5.第四种访问控制级别:不可访问(inaccessible)从基类继承来的,要么是基类的不可访问成员,要么是基类的私有成员。\n6.公有派生(public)基类成员的访问权限在派生类中保持不变。私有派生(private)私有和不可访问成员在派生类中是不可访问的,公有和保护成员这时变成派生类的私有成员。保护派生(protected)将原来的权限降一级使用,即private变为不可访问;protected变为private(VC++不是这样的,见后面实验);public变为protected。访问控制级别实验:#includeusingnamespacestd;classA{private:intx;inty;voidsetx(int);voidshowx();protected:intz;voidsetz(int);voidshowz();public:intw;voidsety(int);voidshowy();};voidA::setz(inta){z=a;};voidA::sety(inta){y=a;};voidA::setx(inta){x=a;};voidA::showx(){cout<<"x="<在类体外面定义成员函数时必须重写类模板。类模板中的友元声明:参见C++primer中文版P5531.普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数。2.类模板或函数模板的友元声明,授予对友元所有实例的访问权。3.只授予对类模板或函数模板的特定实例的访问权的友元声明。向量:向量与数组的区别:向量中存储元素的多少可以在运行中根据需要动态地增长或缩小。向量是类模板具有成员函数。Vector有四个构造函数\n初始化:vectorB(20,1)允许同类型的向量列表相互赋值。向量第一个元素也是从0开始。和数组一样也使用下标操作符[]。Size_type类型参见C++primer中文版P73Size()函数返回vector类定义的size_type型值。不能使用列表初始化向量,但可以先初始化一个数组,然后把数组的内容复制给向量。注意不能使用该方法去初始化一个已经声明或定义过的向量。a.front()和a.begin()区别:a.front()返回的是容器A第一个元素的值a.begin()返回的是迭代器,指向容器的第一个元素泛型算法:与操作对象的数据类型相互独立的算法。第8章多态性和虚函数滞后绑定(动态联编)(latebinding)支持继承的语言但不支持多态就不能说是支持面向对象编程。原来指向小空间(基类)的指针,可以指向大空间(派生类),但是只能指向它的前一部分。原来指向大空间(派生类)的指针,不允许指向小空间(基类)。指针只能继承不能逆向使用。虚特性可继承,virtual可省。当派生类中定义了一个同名的成员函数时,只要该成员函数的参数个数和相应类型以及它的返回类型与基类中同名的虚函数完全一样,则无论是否为该成员函数使用virtual,它都将成为一个虚函数。注释:最好在派生类也加上virtual以增加可读性。C++的virtual方法与Java的abstract方法相同。纯虚函数:在虚函数的声明后面跟“=0”。纯虚函数一旦声明不用定义。java里没有纯虚函数这个概念。C++抽象类的唯一标志是类里有纯虚函数,Java用abstract修饰抽象类。类族:如果通过同一基类派生一系列的类,则将这些类总称为类族。在成员函数内可以调用纯虚函数。因为没有为纯虚函数定义代码,所以在构造函数或析构函数内调用一个纯虚函数将导致程序运行错误。第9章运算符重载及流类库运算符重载就是函数重载Java不支持运算符重载不能重载的运算符是(.、::、*、?:)不能自己定义新的运算符,只能把C++原有的运算符用到自己设计的类上面去。经过重载,运算符并不改变原有的优先级,也不改变它所需的操作数数目。两种形式:友元函数和类函数在友元函数形式中,该运算符函数的形参数量和该运算符“+”的操作数的数量是想等的。作为类的成员函数的运算符的形参数目比它的操作数少一个。\n在C++中可以重载new和delete运算符,重载new时注意参数须设置为size_t,当然UINT也可以,其他的如WORD,DWORD都不行;重载delete是参数应设为void*。下面是一个例子,还模拟了构造函数与new的执行顺序:1.// 重载newdelete.cpp : main project file.2.3.#include "stdafx.h"4.#include "windows.h"5.#include "iostream"6.7.using namespace std;8.using namespace System;9.10.class A11.{12.public:13. A()14. {15. cout << "A()" << endl;16. }17. ~A()18. {19. cout << "~A()" << endl;20. }21. void * operator new(size_t size)22. {23. if (m_kHeap == NULL)24. {25. m_kHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);26.27. if (m_kHeap == NULL)28. {29. return NULL;30. }31. }32.\n1. void *p = HeapAlloc(m_kHeap, 0, size);2.3. if (p != NULL)4. {5. ++m_iNum;6. }7.8. cout << "New" << endl;9.10. return p;11. }12. void operator delete(void *p)13. {14. if (HeapFree(m_kHeap,0,p))15. {16. m_iNum--;17. }18.19. if (m_iNum == 0)20. {21. if (HeapDestroy(m_kHeap))22. {23. m_kHeap = NULL;24. }25. }26.27. cout << "Delete" << endl;28. }29.30.private:31. static HANDLE m_kHeap;32. static int m_iNum;33.};34.35.HANDLE A::m_kHeap = NULL;\n1.int A::m_iNum = 0;2.3.4.int main(array ^args)5.{6. A *a = new A;7. delete a;8.9.10. getchar();11. return 0;12.}13. 结果为:NewA()~A()Delete类型转换函数:\nExplicit关键字说实话,从来没有感觉到这个关键字有用,直到今天。explicit的意思是明显的,和它相对应的一个词是implicit意思是隐藏的。我参考了MSDN和《c++标准程序库》对这个关键字的描述,并参考了网络上对这个关键字的解释。现将它的使用方法和总结记录如下:首先这个关键字只能用在类构造函数。它的作用是不能进行隐式转换。classgxgExplicit //没有关键字explicit的类{public: int_size; gxgExplicit(intsize) { _size=size; }};下面是调用 gxgExplicitgE1(24); //这样是没有问题的 gxgExplicitgE2=1; //这样也是没有问题的 gxgExplicitgE3; //这样是不行的,没有默认构造函数 gE1=2; //这样也是没有问题的 gE2=3; //这样也是没有问题的 gE2=gE1; //这样也是没有问题的 但是假如gxgExplicit修改为Stack,我们的_size代表的是堆栈的大小,那么调用的第二句就显得不伦不类,而且容易让人疑惑。这并不是可以让代码阅读者\n明白和接受的形式,虽然它是合法的(编译器可以通过编译)。这是因为编译器默认情况下有隐式转换的功能,你输入gE2=1就编译成同第一句相同的结果。所以,explicit就派上了用场。修改代码为:classgxgExplicit{public: int_size; explicitgxgExplicit(intsize) { _size=size; }};继续上面的调用: gxgExplicitgE1(24); //这样是没有问题的 gxgExplicitgE2=1; //这样是不行的,关键字取消了隐式转换 gxgExplicitgE3; //这样是不行的,没有默认构造函数 gE1=2; //这样是不行的,关键字取消了隐式转换 gE2=3; //这样是不行的,关键字取消了隐式转换 gE2=gE1; //这样是不行的,关键字取消了隐式转换,除非类实现操作符“=”的重载。这是编译器(vs2005)显示:cannotconvertfrom'int'to'gxgExplicit'。从这里也就看出这个关键字的作用是将编译器隐式转换的功能给屏蔽掉。 MSDN上有一个注意点描述了下面的事实,当构造函数参数超过两个时自动取消隐式转换。例如classgxgExplicit{private: int_size; int_age;public: explicitgxgExplicit(intage,intsize) { _age=age; _size=size; }};这是有没有关键字效果是一样的。那就是相当于有这个关键字。但是另外一种情况例外:其中只有一个必须输入的参数,其余的为有默认值的参数。classgxgExplicit{private: int_size; int_age;\npublic: explicitgxgExplicit(intage,intsize=0) { _age=age; _size=size; }};classgxgExplicit{private: int_size; int_age;int_hight;public: explicitgxgExplicit(intage,intsize=0) { _age=age; _size=size; _hight=hight; }}; 这样的情况下相当于一个参数的效果。到现在为止。这个关键字就是这么用了。