运算符重载
和重载函数很相似,将运算符看作是一种特殊的函数,操作数是函数的参数,运算结果是函数的返回值。
函数名由关键字operator 和其后要定义的运算符组成
operator=, operator<<, operator+
返回类型是运算结果的类型,参数表就是提供参与运算的操作数,参数个数取决于运算符的操作数个数和运算符函数是成员函数还是非成员函数,函数体进行运算、返回运算结果(即表达式的值)
类的成员运算符函数:this 指向的对象被作为运算符的第一个操作数(左)
在类外定义重载运算符,通常定义为类的友元,这也是友元最常见的用法,除此之外用友元很容易破坏类的封装性。
运算符函数只有在类类型的对象参与运算时才起作用,当运算符作用于内置类型的运算对象时,不会改变该运算符原来的含义。
运算符重载后,原有的基本语义不变:
(1)不改变运算符的优先级
(2)不改变运算符的结合性
(3)不改变运算符所需要的操作数
注:重载运算符只是扩展了运算符的应用范围,只是重新定义含义,但不能创建新的运算符
不建议重载的特殊运算符:逻辑与(&&)、逻辑或(||)、逗号运算符(,)
赋值(=)、下标([])、函数调用(())和成员函数访问箭头(->)运算符必须是成员函数
组合与继承
组合
将一个类的对象作为另一个类的成员,被称作组合或包含
成员对象是组合对象的一部分,随着组合对象的创建而创建,随着组合对象的撤销而撤销。成员对象不作为独立元素对外部展现
创建包含对象成员的组合对象时,会执行成员类的构造函数初始化对象成员,成员对象的初始化使用初始化列表语法
当组合对象被撤销时,会执行其析构函数,成员对象的析构函数也会被执行,析构函数的执行次序和构造函数相反
继承
类继承关系的语法形式
class 派生类名 : 基类名表
{
数据成员和成员函数声明
};
访问控制 表示派生类对基类的继承方式,使用关键字:
public 公有继承
private 私有继承
protected 保护继承
派生类构造函数声明为
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )
… 对象成员n ( 变元表 ) ;
构造函数执行顺序:基类 —> 对象成员—> 派生类
基类的构造函数和析构函数不能被继承。如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造
派生类是否定义析构函数与所属的基类无关
派生类构造函数的一般格式(注意:这是基类有构造函数且含有参数时使用)
派生类::派生类名(参数总表):基类名(参数表)
{
// 派生类新增成员的初始化语句
}
多继承声明语法
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
多继承构造函数
派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),…,基类名n(参数表n)
{
// 派生类新增成员的初始化语句
}
赋值兼容规则指在程序中需要使用基类对象的任何地方,都可以用公有派生类的对象来替代。
注意:(1)声明为指向基类的指针可以指向它的公有派生类的对象,但不允许指向它的私有派生类的对象。
(2)允许将一个声明为指向基类的指针指向其公有派生类对象,但是不能将一个声明为指向派生类对象的指针指向其基类的一个对象。
(3) 声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来直接访问派生类中从基类继承来的成员,而不能直接访问公有派生类的定义的成员。
虚函数与多态
纯虚函数说明形式:
virtual 类型 函数名(参数表)= 0 ;
实现运行时多态的关键首先是要说明虚函数,必须用基类指针调用派生类的不同实现版本。基类指针虽然获取派生类对象地址,却只能访问派生类从基类继承的成员。
注意: 一个虚函数,在派生类层界面相同的重载函数都保持虚特性,虚函数必须是类的成员函数,虚函数可以是另一个类的友元,析构函数可以是虚函数但构造函数不能是虚函数。在派生类中重载基类的虚函数要求函数名、返回类型、参数个数、参数类型和顺序完全相同。
纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。
纯虚函数是一个在基类中说明的虚函数,在基类中没有定义, 要求任何派生类都定义自己的版本,纯虚函数为各派生类提供一个公共界面,一个具有纯虚函数的基类称为抽象类。