C++总结
namespce定义可嵌套。
?0值转换为true,0值转换为false
三?运算符
C语言返回变量的值????? C++语言是返回变量本身
1,C语言中的三目运算符返回的是变量值,不能作为左值使用
2,C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方(如果有一个是常量值,则不能作为左值使用)
Const是常变量,const修饰的常量编译期间,就已经确定下来了,由编译器处理的,提供类型检查和作用域检查
宏定义由预处理器处理,单纯的文本替换
引用即别名,实际引用在C++中的内部实现是一个常指针
const 对象的引用必须是 const 的
inline内联 必须和函数定义结合在一起
内联函数由 编译器处理,直接将编译后的函数体插入调用的地方,
宏代码片段 由预处理器处理, 进行简单的文本替换,没有任何编译过程。
函数重载:用同一个函数名定义不同的函数,当函
数名和不同的参数搭配时函数的含义不同。
封装,可以达到,对内开放数据,对外屏蔽数据,对外提供接口。
复制构造函数
A x(2); //直接初始化,调用构造函数
A y = x; //复制初始化,调用复制构造函数
初始化列表中的初始化顺序,与声明顺序有关,与前后赋值顺序无关。
new和delete是运算符,不是函数,因此执行效率高
,静态成员是属于整个类的而不是某个对象,静态成员变量只存储
一份供 所有对象共用。所以在所有对象中都可以共享它。
//声明 在类的内部
static 数据类型 成员变量;
//初始化 在类的外部
数据类型 类名::静态数据成员 = 初值;
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函 数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元 的名称前加上 关键字 friend
运算符重载
左操作数该函数的调用对象 ??右操作数该函数的参数对象
类型兼容性原则
子类对象可以当作父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
构造函数先父后子 ?析构函数先子后父
C++语言中函数的返回值类型的是由在定义该函数时所指定的数据类型决定的成员函数拥有this指针
面向对象程序设计的特征:封装,继承、派生,多态性
当成员函数体在写类的声明内且无循环语句与switch 语句是为内联函数,其余不是内联函数
类继承中,缺省的继承方式是私有。
虚函数实现了C++的多态机制,类实现了C++的封装机制。
复制构造函数的参数是什么形式?
答:复制构造函数是用类的对象给类的另外一个对象赋值,所以构造函数的参数的类的对象。class A
{
public:????????????????????????? 加const 防止拷贝构造函数修改形参的值
A(const A&a);
} ;
拷贝构造函数的作用是用对象初始化对象
对象成员的构造函数调用顺序取决于对象成员在类中声明的顺序
在 C++中,编译系统自动为一个类生成缺省构造函数的条件是该类没有定义任何构造函数
要禁止修改指针p本身,又要禁止修改p所指向的数据,p应定义为const char * const p = “ABCD”;
多态性不同对象调用相同名称的函数
?类与对象???? *为选读
? 1>声明与实现都定义在类内部
? 2>声明在类内部,实现在类外部
??????? 2>类外不能被直接访问,通过公有成员函数访问
??????? 3>默认类型(数据成员常用)
??????? 4>继承关系中,子类不可以访问父类的private成员
?????????? 2>类外不能被直接访问,通过公有成员函数访问
?????????? 3>继承关系中,子类可以访问父类的protected成员
??????? 2>成员函数常用
?????????? 2>功能:为新对象分配内存空间;初始化数据成员
?????????? 3>写法:a.构造函数名与类名相同
?????????????????? b.没有返回时值类型
?????????????????? c.可以重载
d.一般为public(例如:在成员函数里生成对象,可以为私有)
?????????? 4>使用:声明对象(或需要构造新对象)时系统自动调用
?????????? 5>默认构造函数
??????????? (只有一个,无参数/每个参数都有默认值,无函数体)
?????????? 2>功能:撤销类的对象
?????????? 3>写法:a.析构函数名与类名相同,前面冠以~
?????????????????? b.没有参数,返回时值类型
?????????????????? c.不可以重载,只有一个
?????????????????? d.公有
?????????? 4>使用:撤销对象时系统自动调用
?????????? 5>默认析构函数
??????????? (只有一个,无参数/每个参数都有默认值,无函数体)
?????? 2>&是引用类型说明符
?????? 3>声明引用时,必须同时对其进行初始,且不能再把该引用名作为其他变量名的别别名
?????? 4>不能建立数组的引用,只能建立数组元素的引用。
?????? 5>使用:a.引用作为函数参数 --类似于地址传值
????????????? * b.引用作为函数返回值--一般函数返回值时,要生成一个临时变量作为返回值的副本,而用引用作为返回值时,不生成值的副本。
※注意:引用作为函数的返回值的情况:
????? I.全局变量? II.引用参数传递过来的变量
????? ##不能是函数中的局部变量,这时返回的局部变量地址已经失效。
9.复制构造函数:特殊的构造函数
1>功能:用一个已经存在的对象去初始化一个新的同类对象???
? 2>写法:a.函数名与类名相同
???? b.形参是本类对象的引用,无返回值类型
????????? c.默认拷贝构造函数/自定义拷贝构造函数
3>以下情况时,系统自动调用复制构造函数
a.用一个对象初始化另一个对象
* b.函数形参是类的对象,函数形参和实参结合时
* c.函数返回值是类的对象,当函数返回时
10.成员对象与构造函数
1>定义:类中的成员,除了成员数据和成员函数外,还有成员对象,即用
其他类的对象作为类的成员,也称为对象成员,使用成员对象的技术称为聚合。成员对象是实体,系统不仅为它分配内存,而且要进行初始化。
2>构造函数写法:
a. 类名::构造函数名(参数总表):对象成员1(参数名表1),对象成员2(参数名表2),……对象成员n(参数名表n){……}
//参数总表:含数据类型;参数名表:不含数据类型
b. 构造函数可以采用多种方法对数据成员初始化:
3>构造函数调用顺序:
???? 含对象成员的类对象的初始化时,首先依次自动调用各成员对象的构造函数,再执行该类对象自己的构造函数的函数体部分。各成员对象的构造函数调用的次序与类定义中说明的顺序一致,而与它们在构造函数成员初始化列表中的顺序无关。
4>析构函数调用顺序:
因为析构函数没有参数,所以包含成员对象的类的析构函数形式上并无特殊之处。但是撤销该类对象时,会首先调用自己的析构函数,再调用成员对象的析构函数,调用次序与初始化时的次序相反。
11. 运算符重载
1>定义:运算符的重载是特殊的函数重载,必须定义一个函数,并通知C++编译器,当遇到该重载的运算符时调用此函数。对运算符进行定义叫做运算符重载函数,通常为类的成员函数。
2>写法:
a. 返回值类型 operator重载的运算符(参数表){……}
//operator是关键字,它与重载的运算符一起构成函数名。
* b.引用作为参数:const 引用
Complex operator+(const Complex &c){ }?????????
注意:参数采用对象的引用而不是对象本身,调用时不再重新分配内存建立一个复制的对象,函数效率会更高。而在引用形式参数类型说明前加const关键字,表示被引用的实参是不可改变的,如程序员不当心在函数体中重新赋值了被引用的实参, C++编译器会认为出错。
[附加]:const引用可以实现不可寻址的值,或不同数据类型的引用
???? <1>const ?int &q=7;?? q的值不能变
?? ??<2>int p=3;? const ?double &q=p;? => double t=p;?? const ?double &q=t;? //t为临时变量
3>实现:运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函数,而右操作数是该函数的参数。
4>默认的赋值重载运算符
Complex &operator+(const Complex &c){ }???? //返回值类型是为了a=b=c的形式
5>右操作数不是类的对象??? c3=c1+0.6;???? c3= 0.6+c1; (错误,用友元解决)
Complex operator+(const Complex &c){ }? 或? Complex operator+(double c){ }
6>不允许重载的运算符???? ?:??? ./.*??? ::?????? sizeof
12. 友元
?? 1>定义:某一个类的友元(friend)函数不属于该类,但可以在类外访问该类中的任何成员,包括私有数据。友元函数用关键字friend说明。
2>写法:friend complex operator + (const complex &c1,const complex &c2)
//“const 引用”作为参数,可以实现: a+0.6;? 0.6+a;??? a+b
? 3>说明:
a. friend只用于类说明中,定义时不加friend
b.注意友元不是成员函数,但可以直接访问私有成员
c. d+c被C++编译器解释为:operator+(d,c)
d.友元函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护部分,但结果一样。
* 4> 运算符重载的三种形式
成员函数形式 | CInt operator+(const CInt &r); | ||
友元函数形式 | friend CInt operator+(const Cint &r1,const CInt &r2); | ||
全局函数形式 | CInt operator+(const Cint &r1,const CInt &r2); | ||
函数调用 | 特点 | 说明 | |
成员函数形式 | a.operator+(b) | 1.定义为类的成员函数 2.左操作数必须是类的对象 3.右操作数设为函数参数 | 1.左操作数作为当前对象通过this指针访问 2.右操作数通过函数参数访问 |
友元函数形式 | operator+(a,b) | 1.定义为类的友元函数 2.左操作数不一定是类的对象 3.左右操作数按顺序作为函数的参数 | 1.作为类的友元直接访问对象的私有数据成员 2.有些运算符的参数只能为特定类型,如,流插入运算符”<<” |
全局函数形式 | operator+(a,b) | 1.定义为全局函数 2.左右操作数按顺序作为函数的参数 | 一般要通过共有访问函数访问对象的私有数据成员 |
*5> 只能重载为类的成员函数的运算符:
赋值运算符 | ?= |
函数调用运算符 | () |
下标运算符 | [] |
成员访问运算符 | -> |
13.静态成员:是指声明为static的类成员
1>在类的范围内所有对象共享的某个数据,静态数据成员不属于类的某一特定对象,而是属于整个类。
2>无论私有或非私有,必须在类外初始化,用(::)来指明所属的类。
3>静态成员函数只能直接访问类中的静态成员。
4>非静态成员时,必须借助对象名或指向对象的指针。
5>静态成员(变量和函数)可以用类名或对象名访问。
14.指针:
? 1>指向对象的指针---引用成员方式 :-> 或? *.
? * [补充]
a. 指向const对象的指针:?? const int i = 9;const int *p = &i;
//允许给p指针重新赋值,使其指向另一个const对象,但是不允许通过p指针来修改所指对象的值。
b. const指针:???? int i = 0;int *const p = &i;
//const指针的值是不能被修改的,这意味着不能使其指向其他的对象。所以在定义的时候就必须要初始化。
c.指向const对象的const指针:?? const i = 10; const int *const p = &i;
//既不能修改指针p所指向的对象的值,也不允许修改该指针p的指向
2>this指针
a.定义:?只能在一个类的成员函数中调用,它表示当前对象的地址
b.使用:(1) 数据成员与成员函数参数同名时
?????? (2) 成员函数返回值时当前类的对象
15.string 类
? C++的字符串 string类,它重载了运算符,连接、索引和复制等操作不必使用函数,使运算更加方便,而且不易出错。
#include<string>
using namespace std;
16.多文件结构
模板
通用的代码就必须不受数据类型的限制,可以把数据类型改为一个设计参数。这种类型的程序设计称为参数化(parameterize) 程序设计。
17.函数模板:
1>定义:用来创建一个通用函数,支持多种不同类型形参。
2>写法:
template<模板参数表>返回类型 函数名([形式参数表]){……}
// <模板参数表>尖括号中不能为空,参数可以有多个,用逗号分开。
//由关键字 class 或 typename(建议用typename) 后加一个标识符构成。
3>使用:使用函数模板,只需以函数模板名为函数名进行函数调用:
???? ?函数名(数据实参表);
18.类模板:
1>写法:
template<模板参数表> class 类名{};
template<模板参数表> 返回类型 类名<模板参数名表>::成员函数名([形参表]) { }
2>说明:
a.类模板的定义格式与类相同,包含数据成员与成员函数
b.类模板中的成员函数都是函数模板
c.函数声明(声明与定义分开)时不加“template<模板参数表>”
d.模板参数有两种:模板类型参数和模板非类型参数。
3>使用:类模板名 <具体参数类型说明符> 对象名 (初始化参数表)
4>模板非类型参数:表示该参数名代表了一个常量。
19.模板与类参数:
在面向对象程序设计中,函数模板有两种常见的应用方式:
1>函数模板作为类模板的成员函数,在模板类型参数中重载函数与运算符,直接访问私有数据成员,实现通用算法。
2>独立的函数模板(非成员函数)处理模板类(或普通类,或普通数据),以类模板为参数,借助模板类型参数中重载的函数或运算符实现通用算法。
20.动态内存分配
? 1>动态分配与释放
a.分配:当程序运行到需要动态分配变量或对象时,必须向系统申请取得自由存储区中的一块所需大小的存储空间,用于存储该变量或对象。
指针变量名=new 类型名(初始化式);
??? b.释放:当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存储空间,这样系统就能进行再次分配,做到重复使用有限的资源。 delete 指针名;
//这时释放了pi所指的目标的内存空间,也就是撤销了该目标,称动态内存释放,但指针pi本身并没有撤销,该指针所占内存空间并未释放。
C.数组的动态内存分配
|
指针变量名=new 类型名[下标表达式]; ?//“下标表达式”可以是变量表达式
delete[ ] 指向该数组的指针变量名;
??? 特点:i.”下标表达式”可以在运行时确定
????????? ii.如果有char *pc1,令pc1=pc,同样可用delete [ ] pc1来
??????????? 释放该空间。
???????? iii.没有初始化式,不可对数组初始化。
2>自由存储区对象与构造函数
? 通过new建立的对象要调用构造函数,通过delete删除对象也要调用析构函数。
*3>浅复制与深复制
a.浅复制:默认复制构造函数,可用一个类对象初始化另一个类对象,称为默认的按成员复制,而不是对整个类对象的按位复制。这称为浅复制。
b.深复制:重新定义复制的构造函数,给每个对象独立分配一个自由存储区对象,称深复制。
21.继承
1>定义:被继承的类称为基类(base class)或超类(superclass),新的类为派生类(derived class)或子类(subclass)。
2>写法:派生类的定义:
class 派生类名:访问限定符? 基类名1《,访问限定符?
??? 基类名2,……,访问限定符? 基类名n》{
《 private:
????????????? 成员表1;》 //派生类增加或替代的私有成员
《public:
????????????? 成员表2;》 //派生类增加或替代的公有成员
《protected:
????????????? 成员表3;》 //派生类增加或替代的保护成员
};
*3>访问限定符:公有派生是绝对主流
继承方式 | 基类特性 | 派生类特性 (派生类中对基类成员的访问限定?) | 在派生类对象访问基类成员? |
公有继承 | public | public | 可访问 |
protected | protected | 不可访问 | |
private | 不可访问 | 不可访问 | |
私有继承 | public | private | 不可访问 |
protected | private | 不可访问 | |
private | 不可访问 | 不可访问 | |
保护继承 | public | protected | 不可访问 |
protected | protected | 不可访问 | |
private | 不可访问 | 不可访问 |
4〉派生类构造函数
派生类名(参数总表):基类名1(参数名表1)《,基类名2(参数名表2),……,基类名n(参数名表n)》,《成员对象名1(成员对象参数名表1),……,成员对象名m(成员对象参数名表m)》{
……//派生类新增成员的初始化;
} //所列出的成员对象名全部为新增成员对象的名字
5〉派生类构造函数各部分执行次序:
a.调用基类构造函数,按它们在派生类定义的先后顺序,顺序调用。
b.调用成员对象的构造函数,按它们在类定义中声明的先后顺序调用。
c.派生类的构造函数体中的操作。
//注意:
1.如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的默认构造函数。
2. 如果基类定义了带有形参表的构造函数时,派生类就应当定义构造函数,显式给出基类名和参数表。
6>析构函数调用次序与构造函数相反
1〉基类构造函数的调用顺序:
b.处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的顺序无关。
多继承时的重名成员:
2〉在多个基类中有重名的成员:
?? 使用作用域运算符::访问重名的成员
*23. 虚基类
1〉引入:
a.多继承时,发生了重名成员。且这些重名成员来自同一个间接基类。
b.将共同基类设置为虚基类,从不同路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。
2〉写法:
class 派生类名:virtual ?访问限定符? 基类类名{...};
class 派生类名:访问限定符? virtual ?基类类名{...};
3〉构造函数:
派生类名(参数总表):基类名1(参数名表1),……,《成员对象名1(成员对象参数名表1),……,底层虚基类名1(参数名表1)《,……, 底层虚基类名r(参数名表r)》{
};?
//在多层虚拟继承构造函数中,基类名不仅要列出直接基类,而且要列出底层虚基类,否则编译器认为出错。如不是虚拟继承只能列直接基类。
4〉构造函数调用顺序
首先是虚基类的构造函数并按它们声明的顺序构造。
第二是非虚基类的构造函数按它们声明的顺序调用。
第三是成员对象的构造函数。
最后是派生类自己的构造函数被调用。
24.派生类应用讨论
1>派生时的同名覆盖:
a.数据成员的同名覆盖
b.成员函数的同名覆盖
c.使用作用域运算符::访问被覆盖的成员
*2> 赋值兼容规则:
在任何需要基类对象的地方都可以用公有派生类的对象来代替:
*3>继承与聚合:
继承使派生类可以利用基类的成员,如果我们把基类的对象作为一个新类的对象成员,也可以取得类似的效果。派生类采用继承方法,成员对象是聚合的概念。
*4>派生类与模板:
? 模板追求的是运行效率,而派生追求的是编程的效率。?
25.多态性与虚函数
在C++中有两种多态性 |
|
编译时的多态性 |
运行时的多态性 |
|
运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。它是通过类继承关系和虚函数来实现的。目的也是建立一种通用的程序。通用性是程序追求的主要目标之一。 ? |
通过函数的重载和运算符的重载来实现的。 |
|
在C++中有两种多态性 |
|
编译时的多态性 |
运行时的多态性 |
|
运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。它是通过类继承关系和虚函数来实现的。目的也是建立一种通用的程序。通用性是程序追求的主要目标之一。 ? |
通过函数的重载和运算符的重载来实现的。 |
|
在C++中有两种多态性 |
|
编译时的多态性 |
运行时的多态性 |
|
运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。它是通过类继承关系和虚函数来实现的。目的也是建立一种通用的程序。通用性是程序追求的主要目标之一。 ? |
通过函数的重载和运算符的重载来实现的。 |
|
virtual? 返回类型? 函数名(参数表){…}
//关键字virtual指明该成员函数为虚函数。virtual仅用于类定义中,如虚函数在类外定义,不可再加virtual。
//当一个类的某个成员函数被定义为虚函数,则由该类派生出来的所有派生类中,该函数始终保持虚函数的特征。
2>成员函数设置为虚函数的要点:
a.派生类中定义虚函数必须与基类中的虚函数同名外,还必须同参数表,同返回类型。否则被认为是重载,而不是虚函数。
b.只有类的成员函数才能说明为虚函数,这是因为虚函数仅适用于有继承关系的类对象。
c.静态成员函数和内联函数,不能作为虚函数。
d.一个类对象的静态和动态构造是相同的,实现动态多态性时,必须使
用基类类型的指针变量或引用,使该指针指向该基类的不同派生类的对象,并通过该指针指向虚函数,才能实现动态的多态性。
e.析构函数可定义为虚函数,构造函数不能定义虚函数,因为在调用构造函数时对象还没有完成实例化。通常把析构函数定义为虚函数,实现撤消对象时的多态性。
g.函数执行速度要稍慢一些。为了实现多态性,每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现。所以多态性总是要付出一定代价,但通用性是一个更高的目标。
3>纯虚函数: