C++ Primer第十五章 面对对象程序设计 零散知识点


前记:
面对对象程序设计的核心思是数据抽象、继承和动态绑定。
我们可以将类的接口与实现分离:使用继承,可以定义相似的类型并对其相似关系建模
:使用动态绑定可以再一定程度上忽略相似类型的区别,而以同一的方式使用他们的对象。

继承:
通过继承联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类,其他
类则直接或间接地从基类继承而来,这些继承得到地类称为派生类。基类负责定义在层次关系中
所有共同拥有地成员,而每个派生类定义各自特有地成员。

虚函数:
在C++语言中,基类将类型相关地函数与派生类不做改变直接继承地函数区分对待。
对于某些函数,基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数
声明成为虚函数。


派生类
1、通过使用类派生列表来明确指出它是从那个基类继承而来的。 
2、并且派生类必须在其内部对所有重新定义的虚函数进行声明。派生类可以在这样的
函数前加上virtual关键字,但并不是非得这么做。
3、C++允许派生类显式的注明它将使用哪个成员函数改写基类的虚函数。具体措施
是在该函数的形参列表之后增加一个override关键字
 

动态绑定
通过动态绑定,我们能用同一段代码分别处理基类和派生类的对象。
该机制取决于,函数输入的形参是基类还是派生类,然后它会考虑选择哪一个
类的成员函数。

基类都应该定义一个虚析构函数,即使该函数不执行任何实际操作。

成员函数与继承
派生类可以继承其基类的成员,但遇到virtual成员函数时,需要自己提供定义以覆盖
操作是加上override。

基类必须把两种成员函数区分开来:一种是基类希望其派生类进行覆盖override的函数(虚函数);
另一种是基类希望派生类直接继承而不需要改变的函数。
函数会根据引用对象不同调用不同类的成员函数。

virtual 是虚函数的标识,该标志只能出现在类内,而不是类外。理论上,构造函数
之外的任何非静态函数都可以是虚函数。如果一个类把函数声明为虚函数,那么该函数
在派生类中也是虚函数需要,使用override显式覆盖。

访问控制与继承
派生类剋继承定义在基类中的成员,但是派生类的成员函数不一定有权访问从基类
继承来的成员,如私有成员private标识的,派生类无权访问,我们现在需要一个用户代码
无法访问,但是其派生类有权访问的关键字,称为protect(受保护的访问运算符)

派生类
派生类必须通过类的派生列表明确指出他是从哪个(那些)基类继承而来。
继承的方式有private、protected、public
如果一个派生式是public的,则基类的公有成员也是派生类接口的组成部分,此外,
我们能将公有派生类的对象绑定到基类的引用或指针上。

派生类中的虚函数
派生类经常(但不总是)覆盖它继承的虚函数,如果派生类没有覆盖其基类中的某个
虚函数,则该虚函数的行为类似于其他的普通成员,派生类回直接继承其在基类中的版本。

派生类对象及派生类向基类的转换
一个派生类对象包含多个组成部分:一个含有派生类自己定义的(非静态)成员的
对象,以及一个于该派生类继承的基类对应的子对象,如果有多个基类,那么这样的
子对象也有多个。

派生类构造函数
派生类虽然有基类的成员,但是并不可以直接初始化它,和其他创建了基类对象的
代码一样。派生类必须使用基类的构造函数来初始化它的基类部分。
每个类控制自己成员的初始化
每个类初始化顺序,基类、顺序初始化成员 

继承和静态成员
如果基类定义了一个静态成员,则在整个继承体系中只存在该成员的唯一定义
不论从基类中派生出来多少个派生类,对于每个静态成员来说只存在唯一的实例。

派生类声明同普通声明相同。
派生类的派生列表只出现直接基类。

防止继承的发生
在类名后面加上final关键字;
class xx final{};

静态类型和动态类型
当我们使用存在继承关系的类型时,必须将一个变量或其他表达式的静态类型于该
表达式表示对象的动态类型区分开来。表达式的静态类型在编译时总是已知的。
他是变量声明时的类型或者表达式生成的类型;动态类型则是变量或表达式表示内存中的对象的类型。
动态类型则是变量或表达式便是的内存中的对象的类型,运行才知道。
例如 基类引用
当然基类引用或者指针,绑定了派生类的对象,则该应用或指针行为仍然和基类一致。

虚函数
所有虚函数必须有定义。
并且定义形式必须一致。
如果虚函数使用默认实参,则基类和派生类中定义的默认实参最好一致
回避虚函数机制。
当我们特定需要某个虚函数时,用作用域声明
例如 Quote::net_price(44);

抽象基类
含有(或未经覆盖直接继承)纯虚函数的类是抽象基类,抽象基类负责定义接口
而后序的其他类可以覆盖该接口。
我们不能(直接)创建一个抽象基类的对象。

纯虚函数
一个纯虚函数不需要定义,我们通过函数体的位置(在声明语句的分号之前)书写
=0就可以将一个虚函数说明为纯虚函数,其中=0只能出现在虚函数声明语句中。

派生类构造函数只初始化它的直接基类
抽象基类不能定义其对象,
但仍旧可以定义它的引用和指针,可以为多个派生类进行服务。 

派生类的友元,可以访问基类protected成员。
每个类分别控制自己的成员初始化过程,与之类似,每个类还分别控制着其成员对于
派生类来说是否可访问。

继承机制
public继承
派生类可以访问基类的protect成员和public成员,并且基类的protect、public成员
都保留其性质。
private
派生类可以访问基类的protect成员和public成员。此时基类的成员一律被当作派生类
的private成员处理。

前面说的派生类向基类的转换也受此限定。
由于派生类以私有或者受保护的方式进行继承 

不能够继承友元关系,每个类负责控制各自成员的访问权限


派生类可以为它可以访问的名字提供using声明,达到改变成员属性的特点
例如
class Base
{
   protected :
                int i;
}

class De :private Base  //私有继,De的派生类、用户代码均不可访问 i;
{
  public:
       using  Base::i;
}
进行该操作后,De的派生类和用户代码均可以访问到i;当然前提是通过De。

 

继承中的类作用域
在继承中,基类在派生类外面
也就是说,在派生类内找不到名字会到基类中去找。
在继承中,如果派生类定义了和基类相同的名字,那么派生类的名字会隐藏基类的名字。
而不是重载。
如果是动态绑定,它会使用基类成员函数。

虚析构函数
不论是基类的指针指向派生类对象还是派生类的指针指向派生类对象。
delete操作都会先进行派生类的析构,在进行基类的析构

如果基类有一个不可访问或者删除的成员,那么派生类的析构函数将是删除的
因为它无法销毁派生类对象的基类部分。

移动操作与继承
如果基类缺少移动操作,那么也会组织派生类拥有自己的合成移动操作。

派生类在拷贝构造函数或者移动构造函数中,必须显式的使用基类的拷贝或者移动
构造函数。

如果构造函数或析构函数调用了某个虚函数,则我们应该执行与构造函数或析构函数
所属类型相对应的虚函数版本。

容器与继承
当我们使用容器存放继承体系中的对象时,通常必须采用间接储存方式,因为不允许
在容器中保存不同类型的元素,所以我们不能把具有继承关系的多种类型的对象直接存放
在容器当中

也就是说在容器内存放的都是指针而非对象。

 

 

你可能感兴趣的:(C++)