C++

来源:互联网 发布:重庆江北离家纺城源码 编辑:程序博客网 时间:2024/06/07 08:55

C++重点知识


C++多了布尔值的算术类型.(整型)

//ftp://192.168.100.100

开源的库和OC基础.

内存管理,属性,代理.

String 抽象数据类型标准库


C++的引用 类的声明,多态,继承.(文件操作融合)

面向对象是思想不是语言.(计算机是面向过程的)


C->C++(比C多的)->OC(比C++多的)

C++关键在于代码复用性(关键)和安全性.

游戏的类库是C++写的,不是OC.


C++文件构成

头文件: .h 

源文件: .cpp


编译:

G++  用法和gcc一样.


Cout是对象(一般是屏幕)

Cout会自动检测格式.





引用:

pastedGraphic.png

名字不同但指向同一块地址.




 <iostream> 文件流 不需要.h 和C区分(系统的库不用,自己写的要带)


Using namespace std;

Std是名字的空间,起名字是为了防止空间冲突.


Cout<<“hello”<<endl; 

C++效率慢(g++)

Cout是智能输出的.(cout << I << 8)( int i=8);输出就是8,不是I;


命名空间是防止名字重复(像C语言中的重复包含,工程名_小组名_模块名)

Iostream相当于清华大学,std相当于物理系,cout就是要找的.

:: 域解析符


Std::cout<<...<<std::endl;

不加pastedGraphic_1.png

就得每一个加std::


#if 0/1

...

#endif

条件编译




操作系统最好的还是用面向对象来写(目前主流的都是C)


虚拟存储+多任务=操作系统




声明字符串的时候要加 const.(不然会警告)

Const Int *p=”Hello”;


Cout会自动取值(表达式,函数);


Endl是回车;


引用变量是为了类似C的地址参数传递.(交换2个数)

再次注意函数值传递是副本传递.

引用是对现有变量取别名.

Int max=10;

Int &ref=max;

Ref是mac的引用.

Ref没有新的空间.

Ref和max共用同一块空间.


Ref没空间,这几个字母是给编译器的,编译器会维护符号表.也就是说ref是给人看的,实际上变成机器码就还是同一块空间.


C++里面函数传参的机制:

1:值传递

2:引用传递(C没有)


pastedGraphic_2.png

Pox和py是调用的时候动态绑定,不调用不绑定,绑定结束是函数调用结束.(引用传递,并没有重新开辟空间)



引用的缺点:

Swap并没有传递东西,仅仅是符号绑定,(其实也是传递,只是没有数据拷贝,类似空间跳跃)

Swap(m+4,n)这样就不行了,要变量,m+4最后是常量了.




C++的是四不像,既有面向对象也存在多继承,破坏封装性,语法很多,但大多用不到.



OC中的代理,属性,内存管理.




pastedGraphic_3.png

&是引用的意思.参数换成&x,&y也是一样的.引用只是声明才加上&符号.而且引用必须要初始化.

pastedGraphic_4.png

这就是错的,未初始化.

引用只能绑定一次.而且引用&只能是变量,常量不行.

类型也要匹配,double和int


&+变量.


pastedGraphic_5.png

pastedGraphic_6.png

pastedGraphic_7.png


指针是间接的,引用是直接的.


pastedGraphic_8.png

返回局部的引用和返回局部的变量地址一样,没用.

pastedGraphic_9.png

相当于a=9;(a不是局部变量)




类和对象:

类(高级结构体)




pastedGraphic_10.png


类是一种抽象个体,能形容,代表个体的特点.

具体的个体就是类定义的对象.


每个类的对象会有一些自己的特性(比如吃饭的方式不同,但都是人)


pastedGraphic_11.png



pastedGraphic_12.png


pastedGraphic_13.png

Class 类(struct结构体类似)

属性(数据类型)和行为方法(函数)抽象一个类.

在C语言中结构体不能声明函数,但C++可以.


调用一个方法是对对象发送消息.(就是函数调用,但不能这么说,面向对象的思想)

对象都是活的,2个对象可以发生关联.

结构体没有继承等.


Publie:公有方法.(确保公开的都是方法,不对对象产生损害)

Private:私有方法.


C++默认是私有的属性;

pastedGraphic_14.png


pastedGraphic_15.png

可以直接定义.不用加class.


上面是类(没空间),下面的a是对象(有空间); 类也要考虑对齐.

方法不占空间.(函数)



pastedGraphic_16.png

a和b是一样的大小,方法是公用的.(空间存储的都是数据,函数没空间)

a和b不同的是值,也就是属性.


pastedGraphic_17.png

这样写和类就没关系了,是C的风格.绝对不能这样写!

怎么写才能体现这个函数是这个类的呢?(域名的概念)


pastedGraphic_18.png

Std::(域名)

这样就是这个类的成员方法,不是普通函数了.(类的名称+2个冒号)


类的成员方法一般都是通过类的成员去引用.

pastedGraphic_19.png

其中隐含了this指针

pastedGraphic_20.png

Sut类型的指针,指针变量,指向谁不知道.this谁调用就指向谁!


1:类域

2:this默认就是,不用手动添加.



一般属性都是私有的,方法都是公有的.


封装,继承,多态.


pastedGraphic_21.png

属性设成公有的话,就会破坏封装性.


封装对外隐藏关键属性,细节.


面向过程:造汽车全车都得自己造,标准是自己定的.

但是更换轮胎什么的给不了别人,更换麻烦.就是说不能轻易改动.(蛋炒饭)

面向对象:可以捐眼角膜什么的.轮胎,发动机都不用自己造.

一天可以换一样.(鸡蛋盖饭)发动机坏了,只关注发动机就行了.


也就是说复用性.


类外(公有的,publie:)可以通过对象来引用的(有片面性).

pastedGraphic_22.png

非成员方法来访问的.上面的是成员方法,合法的.




(类内可以随意访问,不然没意义了)

类内(成员方法):成员方法要访问成员变量.

成员方法来访问的.(有类域)

pastedGraphic_23.png

这个就不合法了.类外不能访问受保护的成员.


总结:在成员方法内可以访问(带类域的)




类的声明,方法里可以直接写函数定义.



pastedGraphic_24.png

Show可以直接实现.



不写类域的函数就是变成普通函数了,不然this无法定位.

pastedGraphic_25.png



pastedGraphic_26.png

给a发送init消息.


This a调用就指向a


也就是说以后不用考虑是谁的了,直接赋值.



面向对象是围绕对象在操作(初始化,发送消息)



缺省参数(C++的,C没有)

pastedGraphic_27.png

Int b=10是缺省参数.

pastedGraphic_28.png

B没有接收到参数,就调用默认的缺省参数.


pastedGraphic_29.png

Add(,20)这种用法就是错的!


使用缺省参数必须要保证缺省参数在最右边,它的右边开始的参数都必须都是缺省值.(从右到左)

全缺省也可以.

Int add(int a,int b=10,int c=10)


缺省值不一定要用.



函数的重载(overload)(也是C++特有的)


函数名可以一样,但形参(个数,类型)等必须不同.


一般不用返回类型来区分函数的不同,用形参.

pastedGraphic_30.png

调用的就是第一个,形参是空的(void).

pastedGraphic_31.png



pastedGraphic_32.png

这是重定义了,就错了!!


Func()遇到缺省参数和void一起时编译器就纠结了.



pastedGraphic_33.png


上图,二义性了



函数重载大部分都是通过形参个数来判断的.(推荐)


函数的重载体现了多态的一种.


多态:调用的函数名一样,但产生的行为不一样.(通俗的讲)



封装:

结构体(C中体现的,但只是数据封装)


类:自带函数的超级结构体,处理数据的时候不知道用什么函数,类可以避免这种情况.在类中可以查看所有所需要的函数.


pastedGraphic_34.png

Aver求平均成绩的成员函数,成员内部直接拿来用,不用传参.没隔阂.


要访问成员必须要设一个变量(对象),不然没成员.


pastedGraphic_35.png

调用的形式,必须要通过结构体变量去访问成员.


pastedGraphic_36.png

封装性=成员方法+成员变量.



定义类就用class 用struct也可以但是会和C的结构体弄混.


类:Student  (模具)

对象:s

实例化了对象.

S是Student的实例.


不创建对象的话,就没有空间.


类的作用就是创建对象.


S开辟的空间只有math和english的空间,没有方法的空间,方法空间是共用的,存在应用程序的某个空间.



Class和struct的区别在于权限.

Class要求设置权限,默认是private的.

Private(私有的),publie(公开的),protected(继承保护);


永远不要让类里面的数据成员对外暴露.


S在栈上,栈上的数据不可控,都是0或者随机数.

(所以对象要用构造函数初始化)



pastedGraphic_37.png


pastedGraphic_38.png


pastedGraphic_39.png

pastedGraphic_40.png

pastedGraphic_41.png

pastedGraphic_42.png


pastedGraphic_43.png


Stdlib.h

Arc4random() 真正的非算法随机数.



‘\0’不算字符串长度.



初始化就是初始化对象里面的数据成员.

一个对象永远只调用一次.



For里面定义的int i=0;作用域无法出for循环.


写.h的目的是为了给别人分享的时候,只写类的定义和方法的声明.不然代码泄露.



一个类有一个.h和一个.cpp


.h一般放函数的声明,类的声明,宏定义,类型的定义.


定义是要开空间的,声明不用.



全局变量在源文件中.


pastedGraphic_44.png

分开写的话.cpp中要加域解析符.

在函数名前面加



头文件不参与编译(.cpp->.o),只是预处理.


链接的时候编译器会找到函数真正的地址填充(这就是为什么汇编会有很多MOV,都是地址)

链接阶段会出现的错误只有找不到地址.


1:创建一个对象(开空间)

2:初始化(必须的,否则很危险)

3:使用

4:所占用的资源要清理(外部的资源).

5:终止.

(适用所有的语言)

构造函数与析构函数:


构造函数

在创建对象的时候必须要经过初始化的函数.(强制)




pastedGraphic_45.png

pastedGraphic_46.png

pastedGraphic_47.png

构造函数是成员函数,但有区别:

1:没有返回类型(void也不能有!),形参可以随意.

2:函数名要和类名一样.


作用:

用来初始对象.

pastedGraphic_48.png

必须要没viod,无任何返回值


所有的构造函数,程序员本身不会通过对象去调用,编译器自己调用的.



pastedGraphic_49.png

创建对象的时候要传给构造函数的参数,用来初始化.


pastedGraphic_50.png

所有的对象有且必须要调用一次构造函数.


再次强调:构造函数是成员函数,没有返回值,和类名一致,不主动用对象调用构造函数,构造函数是给编译器来用的.构造函数我们一般都会overload(重载).




编译器会调用构造函数,去所有构造函数里找,看哪一个参数类型匹配,找不到会报错.

pastedGraphic_51.png


因为我提供的构造函数的确是有一个参数,但这个参数类型转换是无效的,所以编译无效.




pastedGraphic_52.png

要是自己写了一个构造函数的话,系统就会不使用默认的构造函数.


创建任何对象的时候,要是程序员没写构造函数的话,编译器会使用默认的构造函数,这个构造函数没有参数,什么也不做.







pastedGraphic_53.png


pastedGraphic_53.png


2个构造函数,一个带参,一个不带.

这样就是构造函数重载了.


pastedGraphic_54.png




误区:

构造函数不是用来创建对象的,而是用来初始化的.目前所有的对象都在栈上,(main申请的,new出来的就是堆(动态开辟的)上).



编译器也是通过对象去调用的.(也是用 . 调用的,编译器自动识别)


Free()只能标记为malloc得到的空间地址,不是清除,只是标记可用.


Realloc()有2个参数,第一个为malloc得到的空间地址,第二个为增扩的空间(SIZE+INCREMENTSIZE)*sizeof(类型)

如果原来的空间后面不够大的话,指针要重新接受新的空间,它会自动复制原先的空间里的内容,也就是说会重新开辟新的空间(在原来空间后的空间不够大的话).




以后用类都得用成员函数(思路).



每一次malloc都得free.

Free()之后指针的值并没有变.

都是函数,会有失败的几率,要检测.


pastedGraphic_55.png

New 是关键字,

pastedGraphic_56.png

Delete也是关键字,不是函数,不会失败,不需要检测.



Ptr2指针在栈上,ptr指向的是堆.也就是说,ptr2这个指针还在,但是是野指针了.(指针可以重复使用,释放的只是空间,没有改变指针这个量什么)

pastedGraphic_57.png

开辟5个int;

pastedGraphic_58.png

Delete[] ptr2; []中不用加数字,new会自动记录个数.

Delete后加不加[]看new的时候加不加,统一的.



只要没有被左值,指针就存在,生命周期是在main中.





栈上的对象消失了但是指向的堆上的空间还在,会内存泄露.


对象消失了,但是占用的资源还在,需要手动清理.


pastedGraphic_59.png



pastedGraphic_60.png

析构参数必须为void;


重载构造函数的目的是多元化.

析构函数,也是强制的.

析构就不需要重载.


pastedGraphic_61.png









pastedGraphic_62.png


析构函数的参数必须为void.

析构函数不可以重载.

不主动通过对象去调用析构函数.(系统调用)

pastedGraphic_63.png


系统在对象生命周期即将结束之前调用.也就是说对象最后调用的函数一定是析构.

析构函数不是自杀用的.(是用来清理外部资源的)

pastedGraphic_64.png

析构函数清理的一定是对象外部的资源.对象生命周期结束时内部资源也就随之消失了.


清理的是某个成员占用的外部的某些资源(文件,网络,数据库等).


编译器默认也提供一个析构函数,也是啥也不干.



pastedGraphic_65.png

析构是对象最后一个调用的函数了.



创建一个堆上的对象.

需要一个指针指向堆上的对象.



pastedGraphic_66.png

Ptr在栈上,堆上的对象.(要用指针来指向使用)

传进来的不是字符串,而是地址.也就是说一共有2个Hello,Apple.ptr开辟了空间后,就拷贝了一份.


再次强调对象本身的资源不需要清理.



Main栈里的ptr指向堆上MyString对象,对象指向堆上的字符串.


Delete ptr;

要清理ptr指向的对象,该对象快结束时会触发析构函数,析构函数里的代码是清理_string指向字符串,所以正好全部清理.


OC里的对象全在堆上.


构造和析构都是一种触发机制,不主动调用.




pastedGraphic_67.png

堆上的对象.



pastedGraphic_68.png

栈上的对象.


Bool类型:true-false.


拷贝构造函数

pastedGraphic_69.png

拷贝构造函数,参数是引用的对象.

pastedGraphic_70.png

拷贝完后,2个对象内容一样.


pastedGraphic_71.png

如果没有定义拷贝构造函数,编译器会自动生成一个隐含的拷贝构造函数,也会自动完成数据拷贝.(两块内存拷贝,和权限没关系)


如果用户定义了构造函数但没定义拷贝构造函数,编译器还是会自动生成拷贝构造函数.


也就是说编译器在生成构造函数的时候,有2种一起生成的,构造函数和拷贝构造函数.


编译器自动的拷贝构造函数的缺点:


_string1 和_string2的指向都一样了,都指向hello,world了,

如果其中有一个生命周期结束,另一个就悲催了.

所以要复写.




类的内部对象可以调用任意数据,不管私有的还是公有的.(不过不建议在公有成员方法里调用私有成员)(最多最多在拷贝构造函数里用,但也不建议,破换了封装性)



C++里面不允许成员函数名称和数据成员名称一样,但OC可以.


继承才是面向对象的核心.




_t的变量都是基本typedef出来的.





链表排序:

构造:

数据是ID,头结点不放数据,不管ID,只管next指针指向NULL;


析构:

用另一个指针指向删除节点的后面,然后遍历删除


插入:

头和尾插法;


排序:

(扑克牌)pastedGraphic_72.png

不用开辟另一个链表,在本身上排序.




重点回顾:

1:引用:没有开辟空间,传参,拷贝构造函数重点使用

2:缺省参数:从右往左缺省.重载

3:函数重载:搭配构造函数.函数名相投,参数有区别.不能有二义性.

4:封装性:数据+方法.对应的类找对应的方法.

5:构造,析构函数:类的成员函数,每个类都有,不能主动去调.但编译器还是通过对象去调的.析构参数不能重载,参数为void.




继承性:

pastedGraphic_73.png

pastedGraphic_74.png

pastedGraphic_75.png


pastedGraphic_76.png


pastedGraphic_77.png


pastedGraphic_78.png


pastedGraphic_79.png


pastedGraphic_80.png

pastedGraphic_81.png


已经存在的类表明已经基本没有大问题,不要在原先基础上修改,破坏了封装性.

用继承来扩充.


继承是有权限的.

(OC中的成员函数都是publie的,只有数据成员才有权限控制)



父类-子类

基类-派生类


继承下来的都是模具,不是具体的对象.

变化的都只是模具.


继承可以在没有源代码的基础上(只有机器码)继承.


子类化(继承)



子类增加新的功能:(隐私问题)


父类的私有成员子类里不能直接调用.



继承的原则是:不能操作父类的成员.(破坏封装性),要调用父类的函数.


添加的代码只要管理好自己的成员就行了,如果要操作父类的成员就交给父类的函数.




复写的现象:

父类和子类有同名的函数情况:(两个show()函数)

这种情况叫做函数的复写

父类的show()被复写了,调用的是子类自己的show();

函数想要调用父类的show()要加域解析符(父类名::show());

对象调用的话也是一样(对象名.父类名::show());



复写的目的:

父类提供的函数对子类来说过时了,功能不适用子类.

在没有源代码的情况下复写.

(显式)





什么时候用继承什么时候用指针:(包含和继承)

Has a

Is a

两种逻辑关系.


两个类是否满足is a的关系就是继承.(黄种人是人,所以是继承)


Has a(电脑包含CPU).




引用的一种方法就是创建一个对象引用另一个对象,在调用那个对象的链表头结点.



Set(写)方法和get(读)方法(OC中get省略,直接是函数名).


在继承里的构造和析构函数:


构造:

子类继承了父类的成员.创建对象的时候要把父类的成员变量也初始化了.(构造有N个参数)子类自己的变量可以自己初始化,父类的要调用父类的成员方法.

代码如下:(Child 是子类,Parent是父类)

        Child(int age,int id):Parent(age)//函数原型:函数调用

{

...

}

Child虽然调用2个参数,但只用了id,age是给父类用的;

(孙子类的构造层层调用,类似递归)

体现了封装性.


C++不存在不调用构造函数的对象.


初始化子类的对象时候先初始化父类.




析构:

子类继承了父类,子类只清理自己的外部资源.父类的交给父类自己的析构函数.




gitHub网站(代码)


Stackoverflow(全球问答专业网站)


初始化是会失败的.(打开文件或数据库)

父类初始化成功在是子类

但是析构不能重载,基本不会失败.析构是和构造反着来.是先清理子类的,再是父类的.





析构函数和构造函数是反得.





问题:

pastedGraphic_82.png

如果不手动写后面的传参,父类的age就是是默认的void.



pastedGraphic_83.png

注意字符串要+1;(\0)



pastedGraphic_84.png




构造先有父类才有子类;

析构要清除子类才是父类.






This指针:

This只能在成员内部使用,它指向对象,但不是固定不变的.

人看到的代码和编译器看到的代码不一样.


Return _a+_b+_c;

// return this->_a+this->_b+this->_c;


编译器会把地址传给this,谁调用就指向谁,不能修改this.

This是可以直接访问成员,很特殊的指针.

编译器自动绑定的,只能在成员方法中使用,不能在外面使用.


一般不主动调用,当形参把成员变量的作用域屏蔽的使用,要手动调用.


谁触发了函数,this就绑定谁.

This是一种动态的概念.


每一个成员方法里都有一个隐藏的this指针.








多态:

函数的重载(OC中没有)


父类:Parent p(50);//年纪

子类:Child c(30,2)//年纪和ID


C对象不能赋值给p对象,(c被截断,赋值可以赋值但是只有父类的原来东西被还回去了.注意的是,p反而不能给c赋值,因为c空间太大,p装不满(没有填充规则(补0是没意义的),普通数据没有填充规则),剩下的部分谁都给不了.)


也就是说:

子类可以赋给父类(有意义),父类不能赋值给子类.

这和普通数据转换不同,多了我可以就取需要的,少了就没法扩充.



父类的指针除了指向自己外,也可以指向子类(子类的起始地址叫给父类指针,有一部分截断,但不用就行)



Parent *ptr;//父类指针

Ptr=&c;//c是子类

Ptr->showChild();//报错!因为ptr实际被编译器识别成Parent *类,showChild()函数是子类的,指针找不到.

pastedGraphic_85.png


Ptr->show();//注意:这里调用的是父类的show(),因为ptr指向的是父类的类型空间.


也就是说,对象赋值是空间拷贝.


((Child *)ptr)->show();//这样就是调用子类的了.

(强转只具有临时性)

首先判断是否是普通还是虚函数(virtual修饰).(编译器决定)

看函数之前的指针,这个指针指向的是什么类型的空间.



总之,注意指针指向的空间类型,来判断是父类还是子类的指针.

指针是什么类型就是什么类型的对象去调.

以上都是编译器确定,通过对象.







多态:

运行时确定的.


pastedGraphic_86.png


虚函数

运行时的多态性


Virtual修饰后的函数就是虚函数,不是普通函数了.

如果ptr->show();是虚函数的话,编译器做不了主了,只检测语法,运行时才能判断.


指针调用函数要先确定函数是普通的还是虚函数.普通就是编译器决定的类型.虚函数是运行时决定.


虚函数要有子类的复写才能实现,复写后调用的就是子类的函数,父类的被virtual屏蔽了.虚函数都不会影响到对象调用(对象调用都是编译器决定的),只会影响到指针这类调用!!!虚函数是可以继承的,可以不加了.

虚函数会把真正的对象找出来,也就是说解决了空间大小赋值的问题,是真正的地址(人的角度).


OC中的函数全是运行时判断调用的.(虚函数是可以继承的,子类不用加了.)



总结:编译时决定的是编译器角度,运行时决定的是人的角度.



最后一个知识点:

Static修饰的成员方法:

(OC中的+与-号有关系)

Static可以被对象调用.

没有对象的前提下也可以调用.


用static修饰的函数可以用类名去调用,同时也可以被对象调用.

形式如下:

类名::hello()


但是不能访问成员变量,应为要有对象才会有空间!

OC中-号只能用类的对象,+号只能用类名.

0 0
原创粉丝点击