l 指向常量的指针。
Inta;
Const int *p1 = &a; //p1是指向常量的指针
Intb;
P1= &b; //正确,p1本身的值可以改变
P1= 1; //编译错误,不能通过p1改变所指对象的值
l 指针类型的常量。
Int * const p2 = &a;
P2&b; //错误,p2是指针常量,值不能改变
l void类型指针可以存储任意类型的对象地址。
l 0专用于表示空指针,也就是一个不指向任何有效地址的指针。
Int *p; //声明一个int型指针p。
P = 0; //将p设置为空指针,不指向任何地址。
Ø 细节:空指针也可以用NULL来表示,NULL是一个在很多头文件中都有
定义的宏,被定义为0。
l 复制构造函数
复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特征,其形
参是本类的对象的引用。其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。
下面是声明和实现复制构造函数的一般方法:
Class类名
{
Public:
类名(形参表); //构造函数
类名(类名 &对象名); //复制构造函数
}
类名::类名(类名 &对象名) //复制构造函数的实现
{ 函数体
}
复制构造函数在下面三种情况中会被调用:
1. 当用类的一个对象去初始化该类的另一个对象时:
Intmain()
{
Point a(1, 2);
Point b(a); //用对象a初始化对象b,复制构造函数被调用
Point c = a; //用对象a初始化对象c,复制构造函数被调用
Cout<<b.getX()<<endl;
Return 0;
}
2. 如果函数的形参是类的对象,调用函数时,进行形参和实参结合时:
Voidf(Point p)
{
Cout<<p.getX()<<endl;
}
Intmain()
{
Point a(1, 2);
f(a); //函数的形参为类的对象,当调用函数时,复制构造函数调用
return 0;
}
3. 如果函数的返回值是类的对象,函数执行完成返回调用者时:
Point g(){
Point a(1, 2);
returna;
}
Int main() {
Point b;
//函数的返回值是类的对象,返回函数值时,调用复制构造函数
b = g();
return 0;
}
l 友元关系提供了不同类或对象的成员函数之间、类的成员函数与一般函数之
间进行数据共享机制。通俗地说,友元关系就是一个类主动声明哪些其他类或者函数是它的朋友,进而给他们提供对本类的访问特许。
1. 友元函数
友元函数是在类中用关键字friend修饰的非成员函数。友元函数可以是一个
普通的函数,也可以是其他类的成员函数。虽然它不是本类的成员函数,但是在它的函数体中可以通过对象名访问类的私有和保护成员。
2. 友元类
同友元函数一样,一个类可以将另一个类声明为友元关系。若A类为B类的
友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员。声明友元类的语法形式为:
Class B
{
… //B类的成员声明
Friend class A //声明A为B的友元类
}
l 虚基类
虚基类的声明是在派生类的定义过程中进行的,其语法形式为:
Class 派生类名::virtual 继承方式 基类名
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。声明了虚基类之后,虚基类的成员在进一步派生过程和派生类一起维护同一个内存数据副本。
l 访问控制
1. 公有继承
当类的继承方式为公有继承时,基类的公有成员和保护的访问属性在派生类
中不变,而基类的私有成员不可直接访问。
2. 私有继承
当类的继承方式为私有继承时,基类的公有成员和保护成员都以私有身份出
现在派生类中,而基类的私有成员在派生类中不可直接访问。
3. 保护继承
保护继承中,基类的公有成员和保护成员都以保护成员的身份出现在派生类
中,而基类的私有成员不可直接访问。
l 运算符重载
运算符的重载有两种形式,即重载为类的非静态成员函数和重载为非成员
函数。运算符重载为类的成员函数的一般语法形式:
返回类型 Operator 运算符(形参表)
{
函数体
}
运算符重载为非成员函数的一般语法形式:
返回类型 operator 运算符(形参表)
{
函数体
}
返回类型指定了重载运算符的返回值类型,也就是运算符结果类型;operator是定义运算符重载的关键字;运算符即是要重载的运算符名称,必须是C++中可重载的运算符,比如要重载加法运算符,这里就写+;形参表中给出重载运算符所需要的参数和类型。
l 虚函数
一般虚函数成员的声明语法是:
virtual 函数类型函数名(形参表);
这实际上就是在类的定义中使用virtual关键字来限定成员函数,虚函数声
明只能出现在类定义中的函数原型声明中,而不能在成员函数实现的时候。
运行过程中的多态需要满足3个条件,第一是类之间满足赋值兼容规则,第二是要声明虚函数,第三是要由成员函数来调用或者是通过指针、引用来访问虚函数。
l 纯虚函数和抽象类
纯虚函数的声明格式:
virtual 函数类型函数名(参数表)=0;
实际上,它与一般虚函数成员的原型在书写格式上的不同就在于在后面加了”=0”。声明为纯虚函数之后,基类中就可以不再给出函数的实现部分。纯虚函数的函数体由派生类给出。
带有纯虚函数的类是抽象类。抽象类的主要作用是通过它来为一个类族建立一个公共的接口,使它能够更有效地发挥多态特性。
抽象类不能实例化,即不能定义一个抽象类的对象,但是可以定义一个抽象类的指针和引用。
l 函数模板与类模板
所谓参数化多态性,就是将程序所处理的对象的类型参数化,使得一段程
序可以用于处理多种不同类型的对象。
函数模板的定义形式是:
template 函数名(参数表)
{
函数体的定义
}
使用类模板使用户可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数,返回值或局部变量能取任意类型(包括系统预定义的和用户自定义的)。
类模板声明的语法形式是:
Template <模板参数表>
Class 类名
{
类成员声明
}
如果需要在类模板以外定义其成员函数,则要采用以下的形式:
Template<模板参数表>
类型名类名<模板参数标识符列表>::函数名(参数表)
一个类模板声明自身并不是一个类,它说明了类的一个家族。只有当被其他代码引用时,模板才根据引用的需要生成具体得类。使用一个模板类来建立对象是,应该按如下格式声明:
模板名<模板参数表> 对象名1,…,对象名n;
l 泛型程序设计的基本概念
我们可以用概念(concept)来描述泛型程序设计中作为参数的数据所需具备
的功能。这里的“概念”是泛型程序设计的一个术语,它的内涵是这些功能,它的外延是具有这些功能的所有数据类型。例如:“可以用比大小、具备公有复制构造函数并可以用‘=’赋值的所有数据类型”就是一个概念,可以把这个概念记作Sortable。具备一个概念所需要功能的数据类型称为这一概念的模型(model)。例如int数据类型就是Sortable概念的一个模型。对于两个不同的概念A和B。如果概念A所需求的所有功能也是概念B所需求的功能(即概念B的模型一定是概念A的模型),那么就说概念B是概念A的子模型。我们把”可以比大小的所有数据类型”这一概念记为Comparable,那么Sortable就是Comparable的子概念。
l 适配器
适配器(adapter)是指用于为已有对象提供新的接口的对象,适配器本身一般
并不提供新的功能,只是为了改变对象的接口而存在。
l Typeid
typeid用于返回指针或引用所指对象的实际类型。注意:typeid是操作符,
不是函数! 运行时获知变量类型名称,可以使用 typeid(变量).name(),需要注意不是所有编译器都输出"int"、"float"等之类的名称,对于这类的编译器可以这样使用:float f = 1.1f; if(typeid(f) == typeid(0.0f) )。
l STL简介
标准模板库(Standard Template Library,STL)最初是由HP公司的Alexander
Stepanov和MengLee开发的一个用于支持C++泛型编程的模板库,1994年被纳入了C++标准,成为C++标准库的一部分。
STL四种基本组件:
1.容器(container)
容器是容纳、包含一组元素的对象。容器类库中包括7种基本容器:向量(vector)、双端队列(depue)、列表(list)、集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)。这7种容器可以分为两种基本类型:顺序容器(sequence container)和关联容器(associative container)。顺序容器将一组具有相同类型的元素以严格的线性形式组织起来,向量、双端队列和列表容器就属于这一种。关联容器具有根据一组索引来快速提取元素的能力,集合和映射容器就属于这一种。
2.迭代器(iterator)
迭代器提供了顺序访问容器中每一个元素的方法。对迭代器可以使用”++”运算符来获取指向下一个元素的迭代器,可以使用”*”运算符访问一个迭代器所指向的元素。
3.函数对象(functionobject)
函数对象是一个行为类似函数的对象,对它可以像调用函数一样调用。任何普通的函数和任何重载了”()”运算符的类的对象都可以作为函数对象使用,函数对象是范化的函数。
4.算法(algorithm)
STL包含70多个算法,这些算法覆盖了相当大的应用领域,其中包括查找算法、排序算法、消除算法、计数算法、比较算法、变换算法、置换算法和容器管理等。这些算法的一个最重要的特征就是它们的统一性,并且可以广泛用于不同的对象和内置的数据类型。
l STL中3种顺序容器的特性比较
操作 | 向量(vector) | 双端队列(deque) | 列表(list) |
随机访问 | 快 | 较慢 | 不能 |
头部插入 (push_front) | 没有push_front 只能用insert完成 | 快 已有的迭代器失效,指针、引用不会失效 | 快 已有的迭代器、指针、引用都不会失效 |
头部删除 (push_back) | 没有push_back 只能用erase完成 | 快 只会使被删除元素的 迭代器、指针、引用失效 | |
尾部插入 (push_back) | 快 当发生容器扩展时,会使所有已有的迭代器、指针、引用失效; 否则不会使任何已有迭代器、指针、引用受到影响。 | 快 已有的迭代器失效,指针、引用不会失效 | 快 已有的迭代器、指针、引用都不会失效 |
尾部删除 (pop_back) | 快 只会使被删除元素的迭代器、指针、引用失效 | ||
任意位置 插入(insert) | 插入位置越接近头部越慢。当发生容器扩展时,会使所有迭代器、指针、引用失效,否则只会使插入位置之后的迭代器、指针、引用失效 | 位置越接近中间越慢。
会使所有的迭代器、指针、引用失效 | 快 已有的迭代器、指针、引用都不会失效 |
任意位置 删除(erase) | 删除位置越接近头部越慢。只会使删除位置之后的迭代器、指针、引用失效 | 快 只会使被删除元素的迭代器、指针、引用失效 |
新闻热点
疑难解答
图片精选