C总结.docx

上传人:b****6 文档编号:8901206 上传时间:2023-05-15 格式:DOCX 页数:14 大小:23.13KB
下载 相关 举报
C总结.docx_第1页
第1页 / 共14页
C总结.docx_第2页
第2页 / 共14页
C总结.docx_第3页
第3页 / 共14页
C总结.docx_第4页
第4页 / 共14页
C总结.docx_第5页
第5页 / 共14页
C总结.docx_第6页
第6页 / 共14页
C总结.docx_第7页
第7页 / 共14页
C总结.docx_第8页
第8页 / 共14页
C总结.docx_第9页
第9页 / 共14页
C总结.docx_第10页
第10页 / 共14页
C总结.docx_第11页
第11页 / 共14页
C总结.docx_第12页
第12页 / 共14页
C总结.docx_第13页
第13页 / 共14页
C总结.docx_第14页
第14页 / 共14页
亲,该文档总共14页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

C总结.docx

《C总结.docx》由会员分享,可在线阅读,更多相关《C总结.docx(14页珍藏版)》请在冰点文库上搜索。

C总结.docx

C总结

一、类和对象进阶;

(1)、对象数组:

a)就是用类来声明一个数组,其中的每个元素都是一个对象。

初始化:

StudentaSA[4]={Student(1,”Li”,98),Student(2,”BIll”,78),Student(3,”Wang”,66)};

调用四次构造函数

(2)、this指针:

a)指向该类对象的指针,成员函数可以通过它访问该类对象的数据成员,由编译器自动产生。

b)同一个类的多个对象公用一份成员函数,以节省空间,而编译器调用成员函数的时候都在参数传入位置第一个增加:

X(类名)const*this,然后将该对象的地址作为实参传递给相应的this指针。

c)不能将this指针的说明写出,否则将出现编译时间错误。

d)当运算符重载和建立双向链表的时候u,显示使用this指针很重要。

this指针一般用于返回当前对象自身

e)This指针指向一个对象,那么不能这样使用this->A:

:

A,只能是this->A,orA:

:

A.

(3)、传值调用与传址调用(引用):

a)Voidf(PointX){……}

PointS;

f(S)→此S作为参数传入,但是相当于在f的里面产生了一个临时的对象X,然后对X操作,并不对S产生影响,函数后S无改变。

b)Voidf(Point&X){……}

PointS;

f(S)→S用引用传入,不会调用构造函数,没有临时的对象产生。

而对X的操作会直接影响S的内容。

c)Voidf(Point*X){……}

PointS;

f(&S)→把S的地址传入,然后赋值给X指针,是最简单的地址传入,但是不鼓励,因为比较不直观。

(4)、类的静态成员

a)采用局部静态变量可以减少全局变量的使用。

b)将全局变量声明为静态可以降低全局变量的副作用。

c)在类A中有static的成员变量(例如staticintM),那么在类声明外面必须要写上一个intA:

:

M;

d)类中的static成员变量是公用的,就是说若干个同类的不同对象都是用一个static变量,他们互相影响。

e)对象的生存空间:

析构顺序:

global对象外围声明static对象局部static变量main中的对象子函数或花括号中的对象。

f)类的static函数有2点要注意:

1、不能用this指针,因为其不属于任何一个对象,所有对象公用一个。

2、static函数只能对static变量操作,如果要对非static的必须是“对象.变量”的方式指明是哪个对象的变量。

g)类的static变量必须在外部声明一下,初始化也必须在外部,不能再初始化列表里。

结构是:

类型类:

:

变量名(=初始值,ifnecessary)。

(5)、友元:

a)友元函数不是成员函数,一般放在public的定义中,但可以访问类的私有的成员变量。

如果需要一个函数同时访问多个类,则它可以定义为多个类(不一定相同)的友元函数。

友元函数没有this指针。

b)友元类:

如果A类是B类的友元(即在A类中声明了B是friend),则B类的所有成员函数都可以访问A的成员。

但A不是B的友元。

c)同名的成员函数和友元函数如果都符合调用的条件,那么就优先考虑成员函数。

比如运算符重载。

(6)、左值:

所谓左值,即指一些可以被赋值的变量,通常在赋值式的左边。

而且,数组名不能是左值,静态变量也不能是左值。

(7)const:

1、const的变量必须用变量初始化列表在初始化

2、如果给一个类定义了一个const的对象,那么该对象就不能调用类中的non-const的成员函数了。

3、我们可以把一个non-const的变量的赋值给一个const的指针:

inta;constint*ptr=&a;这样我们就不会对这个ptr进行操作而改变a的值(如果有类似*ptr=5之类的语句会报错,出错是在指针上)。

但是,我们不能将一个const的变量赋值给一个non-const的指针。

4、const数组是不能用初始化列表初始化的。

5、const函数内部不能对类的成员变量进行改变值的操作。

6、类中如果有同名的非const成员函数和const成员函数,优先调用非const的(当然是在非const的情况下)。

const函数可以和非const版重载,参数a是非const的,调用非const版

任何不会修改数据成员的函数都应该声明为const类型(改错题)

二、构造函数

Newdelete运算符。

构造函数为对象分配空间,但是对象指针不分配空间。

(1)、拷贝构造函数的一些常识:

1、拷贝构造函数是默认的,每个类都用,不自定义系统会默认。

2、默认的拷贝构造函数包含位拷贝,以及析构等功能。

3、默认的拷贝构造函数会造成多个对象指向同一个内存的现象。

4、拷贝构造函数只有在初始化时才调用,在赋值时是不调用的。

5、自定义拷贝构造函数可以新建一个数据内容区(当然需要声明),使不同的对象指向不同内存,从而避免互相影响。

(2)、拷贝构造函数被调用的情况:

1、用类的一个对象去初始化该类的另一个对象时:

例:

PointA(1,2);PointB(A);或者PointB=A;

2、如果函数的形参是类的对象,调用函数时,进行形参和实参结合:

例:

PointA(1,2);f(A);这个不一定是引用的传入。

注意像此类的传入,如果f()函数是一个f(PointB),则会造成调用拷贝构造函数,则产生了一个指向同样内存的B,若对B进行内容操作,则会影响A的内容,若对其在f()结束后析构,则A指向的内容也被析构掉。

此时的解决方法一般是f(Point&B)用引用传入,不调用拷贝构造函数。

或者采用自定义拷贝构造函数,使B生成时指向一个新的内存,其内容拷贝原内存的数据,而对B的操作不会对A有影响。

3、如果函数的返回值是类的对象,函数执行完成返回调用者时:

例:

PointA(1,2);returnA;return是在子函数中。

在3的情况中,要注意,当在一个子函数中return一个对象时,若该对象是子函数的局部,返回时,要自动产生一个临时对象(调用默认的拷贝构造函数),而返回后,临时对象将被销毁,将调用析构函数,此时该对象的存内容的内存已经被释放,则在后面如果还要访问其成员函数或变量则会报错。

(此时一个解决方法是返回对象的指针或者对象引用,但不一定可行)。

还有一个方法是自定义一个拷贝构造函数。

但是,如果返回时在返回类型声明为引用,则不会调用拷贝构造函数,也不会生成临时变量。

(3)、临时对象:

1、临时对象主要是在子函数中返回对象的时候产生的,例如returnA;

2、临时对象在返回的时候就会被析构掉,所以不是很安全。

3、临时对象是一种const对象。

4、其实有的时候,不仅仅是会为传入的对象建临时对象,传入指针的时候也可以。

一般的f(类型*指针名)都是会为指针创建一个临时的复制品的。

只不过原型和复制品指向同一个地址,此时如果对其进行new的操作会出问题,因为其实new的是复制品,而原型并没有任何变化。

但是一般的值的操作是一样的。

(4)、转换构造函数

classname(一个形参){对类中的变量处理};可以构造一个对象。

(5)、类型转换函数

operator类型名(){实现转换的语句};可以把一个对象转换成另外一个类型的数据。

(6)、指向公有成员函数的指针

定义方式:

数据类型(类名:

*指针名)(参数列表)

使用时只需要把成员函数的入口地址赋给她就好:

p=&A:

func;调用时的形式为(类名。

*指针名)(参数列表);相当于调用该函数。

三、继承

(1)、继承的权限:

1、public继承:

将基类的public和protect权限不变,而private不能使用。

2、private继承:

将基类的public和protect继承为private,而private不能使用。

3、protect继承:

将基类的public和protect继承为protect(可以被派生类的成员函数使用,对外界隐藏),而private不能使用。

(2)、private继承和其他继承的区别,主要在于private继承一次后若再想更一层继承,则其成员变量和函数对子类的子类不开放了。

(3)、在继承时,基类的构造函数和析构函数是不被继承的,所以在建立派生类对象时,系统只执行派生类的构造函数,而不会调用基类的。

所以在初始化变量的时候,应当在派生类的构造函数中手动调用基类的构造函数。

此时若派生类中还有对象成员时,其构造函数也要调用,总的格式如下:

如:

派生类构造函数名(参数表):

基类构造函数名(参数表),对象成员名(参数表){……};

而此时调用的顺序一般是基类的构造函数→对象成员的构造函数→派生类的构造函数。

7)#include

usingnamespacestd;

classA

{

private:

intx;

public:

A(inty=0):

x(y)

{

cout<<"A(x)="<

}

intxvalue(){returnx;}

};

classB:

publicA

{

protected:

intx;

public:

B(inty=1):

A(y),x(y+1)

{

cout<<"B(x)="<

}

changex(inty)

{

x=y;

cout<<"changedx="<

:

xvalue()<<";"<

:

xvalue()<

}

intxvalue(){returnx;}

};

classC:

publicB

{

private:

Axa;

intx;

public:

C(inty=2):

xa(y+1),B(y+2),x(y)

{

cout<<"C(x)="<

}

changex(inty)

{

x=y;

cout<<"changedx="<

:

xvalue()<<";"<

:

xvalue()<<";"<

:

xvalue()<

}

intxvalue(){returnx;}

};

main()

{

Aa;

Bb;

Cc;

c.changex(8);

}

答案:

A(x)=0

A(x)=1

B(x)=2

A(x)=4

B(x)=5

A(x)=3//主要是这3步,为什么A(x)=3会是在A(x)=4,B(x)=5后面?

在C的初始化列表中xa(y+1)可是排在B(y+2)前面的啊,那么应该是对xa构造一个对象,所以是A(x)=3啊?

C(x)=2

changedx=4;5;8

(4)、二义性,注意消除二义性(一般都是出现在多重继承的情况下),采用A:

:

f()等标明”类:

:

成员”的方式可以有效消除。

(5)、虚基类:

在第一级继承时就要将共同基类设计为虚基类,用以解决多继承的二义性问题。

其调用的规则为:

1、若同一层次包含多个虚基类,则构造函数按他们说明的先后顺序调用,非虚基类也同理。

2、若虚基类由非虚基类派生来,则仍先调用其基类构造函数,再调用虚基类的构造函数。

3、若同一层中同时包含虚基类和非虚基类,则先调用虚基类的构造,再非虚基类的构造,最后才是派生类的。

(6)、赋值兼容原则(公有继承):

可以用派生类对象给基类对象赋值,或者初始化基类对象的引用,或者用其地址给基类对象的指针赋值。

其实是将派生类中的继承过来的量和基类关联,其派生类特有的不参与。

1、不能将派生类对象的指针指向其基类的对象。

2、通过指向基类指针可以指向它的公有派生对象,到不能指向私有派生对象。

3。

这种指针只能访问从基类中继承的共有成员,不能访问派生类本身的成员。

2)8分每错2分

classA

{

public:

virtual~A(){}

virtualvoidf()const=0;

};

classB:

publicA

{

int*m_id;

public:

B(intval):

m_id(newint(val)){}

~B(){deletem_id;}

voidf()const;

};

四、OverloadingandDefaultParameters(重载与缺省参数)

(1)、我们不能够在return值上用重载

比如:

voidf();intf();是不行的。

(2)、我能够调用一个函数,而不去管她的返回值类型,只需确保我们的变量类型是其中之一:

比如:

intx=f( );.//其中f()为重载的函数,无视其返回值,因为有的时候我和compiler都不能明确到底调用了哪一个。

(3)、重载只是给使用者方便,对于实现者来说,还是需要把所出现的情况重复地进行编程定义实现。

(4)、运算符重载:

1、成员运算符函数重载为双目时,左边的一个参数往往是其本身的,由*this指针给出,而右边的操作数则传入参数获得。

2、成员运算符函数重载为单目时,操作数就是本身,由*this指针给出,不需要参数了,,比如说++,若是++a则重载为operator++();若是a++则重载为operator++(0),0只是摆设,无意义,起区分的作用。

之所以用到*this,主要是在return时。

3、当运算符函数重载为friend的时候,则要全部传入要使用到的参数了,不能用*this。

五、多态和虚函数

(1)虚函数注意:

1、必须用指向基类的指针或引用访问虚函数,此时多态性才能实现。

2、虚函数作为动态联编的基础,必须在继承体系下才能实现。

3、虚函数不能使友元,其调用要靠特定的对象来决定改激活哪个函数,但虚函数可以在另一个类中被声明为友元。

4、虚函数不能是静态的,因为静态函数不受限于某个对象。

5、内联函数不能是虚函数,故即使虚函数在内部定义了,仍是非内联的。

6、构造函数不能是虚函数,因为在构造时,对象还是一片未定的空间,只有在之后,对象才能成为一个类的名副其实的实例。

7、析构函数可以是虚函数。

8、采用对象名额点算符调用虚函数,如a.display(),这时仅仅是静态联编。

9、对于基类,最好声明一个virtual的析构函数,避免部分释放问题。

(2)、抽象类(即含有至少一个纯虚函数的基类):

1、只能用作基类,不能建立对象。

2、不能用作参数类型,函数返回类型。

3、可以声明抽象类的引用和指针然后将派生类的地址或者对象赋值给它,从而访问派生类。

(3)、在delete一个对象指针的时候,该对象的析构如果不是虚函数,则就调用其本身的析构函数,而不调用其derived出的对象的析构。

(如果是继承关系的话)

六、模板

(1)函数的声明和定义必须放在同一个.h文件中。

(2)模板不会节省空间,不会提高效率,只是不需要人工罢了。

(3)用char*类型实例化时,模板函数比较的是2个字符串地址的大小,而不是2个字符串内容的大小,一般来说,后声明的字符串等的地址较大。

(4)、重载函数的调用次序:

寻找一个参数完全匹配的函数,所找到则调用→寻找一个函数模板,将其实例化产生一个匹配的模板函数→寻找重载函数中有无通过类型可产生匹配的函数。

(5)、函数模板中允许使用多个类型参数,但是应当注意template定义部分的每一个模板参数前必须有关键字class。

(6)、在template语句与函数模板定义语句之间不允许有其他的语言。

必须挨在一起。

(7)、模板函数类似于重载函数,函数被重载的时候,在每个函数体内可以执行不同的动作,但同一函数模板实例化后的所有模板函数都必须执行相同的动作。

执行动作(即函数内容)不一样就不能用模板。

(8)、虽然函数模板中的模板形参T可以实例化为各种类型,但实例化的各模板实参之间必须保持完全一致的类型,否则会发生错误。

模板不具有隐式的类型转换。

若要实现不同的类型,则加下标是T多元化,相当于有多种T吧。

T1、T2……

(9)、函数模板其实是一个道理。

必须实例化为模板类后才使用。

当类中的成员函数在类之外定义的话,要像声明类模板一样进行声明,使之成为一个函数模板。

(10)、类模板的语法形式为:

Template

Class类模板名{//类模板体};

(11)、类模板必须用类型参数将其实例化为具体的模板类后,才能用来生成对象,一般形式为:

类模板名<模板实参表>对象名(类实参表)。

其中,模板实参表示将类模板实例化为一般类时所需要的某个具体的类型。

(12)、使用类模板:

1、在程序的头文件中说明类模板的定义。

2、在适当的地方创建一个模板类的实例,即一个实实在在的类定义,同时创建类的对象。

3、有了对象名,以后的使用就和通常一样了。

七、STL

(1)、名字空间:

1、在类库中,有很多重名的变量和函数名,在调用的时候我们一般用”类名:

:

变量名/函数名”的方式放在冲突。

2、还有一种方式就是利用usingnamespacexx来实现。

意思就是以下的程序部分就默认是xx中的变量/函数,当然,可以用其他的来覆盖的吧!

比如我们常见的usingnamespacestd就是指std库的。

3、当然可以只添加一部分的namespace,比如usingstd:

:

cout就只是把cout添加到当前的namespace中去。

(2)、IteratorCategories:

Input(用来从一些container中readdata,只能往前)、Output(用来writedata给container,也只能往前)、Forward(相当于Input+Output)、Bidirectional(likeForward,但是可以backward)、Randomaccess(任意啦!

一般的形式是:

IteratorCategoryname(containername)比如:

std:

:

istream_iteratorinputInt(cin);

(3)、vector向量(可以被认为是一个容器,能存放任意类型的动态数组。

)用法:

Vector<类型>数组名[数组长度]

然后一个个地想数组一样的赋值。

也可以用数组名.pushback[xx]将xx压入数组中。

也可以如下定义vector向量,即缺省数组长度,

Vector<类型>数组名

那么只需在后面进行pushback的时候,它会自动的增加长度的。

在访问vector中的元素的时候,可以采用:

1、数组下标的方式,2、迭代器。

后者可以防止越界访问的错误。

3,常用的函数:

pushback,size,capacity,insert,erase,clear,begin,end,front,at等。

(4)、list线性表:

对于这种线性表,有很多不同于一般链表的性质,比如可以直接经由list.sort()函数就可以进行排序,很方便简洁。

同时与vector一样,也可以用迭代器来遍历。

数据结构内部的载入值和vector差不多,但是在处理具体问题的时候效率不同,对于vector来说,其在内存中是连续的存储空间,而list籍由指针进行跳转。

遍历以及查找的速度较快。

(5)、map映射:

八、异常处理:

(1)、主要就是通过try来进行语句段的检查,如果有问题就throw出一个值。

然后被紧跟的catch接住进行处理。

注意几点就是了:

1、可以跟多个catch,但是每个catch的传入类型必须不同,2、catch接住的是类型,具体值是什么意思则在catch的函数体中写,3、try中如果有调用函数,也可以在子函数体中进行异常处理,throw出来,也会被try后面的catch处理。

(2)、可以用catch(…){…….}来捕获全部的异常,中间的…就起了这个作用。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2