面向对象程序设计

来源:互联网 发布:电脑深度清理软件 编辑:程序博客网 时间:2024/06/01 18:32

1、面向对象程序设计的三个基本概念:数据抽象、继承和动态绑定。

继承对编程的影响:我们可以更容易地定义与其他类相似但不完全相同的新类。

动态绑定对编程的影响:使用彼此相似的类编写程序时,我们可以在一定程度上忽略掉它们的区别。

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

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

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

class Quote {

public:

std::string isbn() const;

virtual double net_price(std::size_t n) const;

};

5、派生类列表

派生类必须通过派生类列表(class derived list)明确指出它是从哪个(哪些)基类继承而来。派生类列表的形式:首先是一个冒号,后面紧跟以逗号分隔的基类列表,其中每个基类前面都可以有访问说明符:

class Bulk_quote : public Quote { //Bulk_quote继承了Quote

public:

double net_price(std::size_t ) const override;

};

派生类必须在其内部对所有定义的虚函数进行声明。派生类可以在这样的函数之前加上 virtual 关键字,但是并不是非得这么做。C++11新标准允许派生类显式地注明它将使用哪个成员函数改写基类的虚函数,具体措施是在该函数的形参表之后增加一个 override 关键字。

6、动态绑定

在C++语言中,当我们使用基类的引用(或指针)调用一个虚函数时将发生动态绑定。

7、虚析构

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

8、成员函数与继承

1、C++语言中,基类必须将两类成员函数区分开来:

1)一种是基类希望派生类进行覆盖的函数(基类通常将其定义为虚函数virtual),当我们使用指针或引用调用虚函数时,该调用将被动态绑定;

2)另一种是基类希望派生类直接继承而不要改变的函数。


2、任何构造函数之外的非静态函数都可以是虚函数。关键字virtual只能出现在类内部的声明语句之前,而不能用于类外部的函数定义。如果基类把一个函数声明成虚函数,则该函数在其派生类中隐式地也是虚函数。

3、成员函数如果没有被声明为虚函数,则其解析过程中发生在编译时而非运行时。

4、派生类可以访问基类的public成员和protected成员,但不能访问private成员。如果基类希望它的派生类有权访问该成员,同时禁止其他用户访问。我们用受保护的(protected)访问运算符说明这样的成员。

9、因为派生类对象中含有与基类对应的组成部分,所以我们能把派生类的对象当成基类对象来使用,而且我们也能将基类的指针或引用绑定到派生类对象中的基类部分上。

这种转换通常称为派生类到基类的类型转换。这种隐式特性意味着我们可以把派生类对象或者派生类对象的引用或指针用在需要基类引用的地方。

注:在派生类对象中含有与基类对应的组成部分,这一事实是继承的关键所在。

10、派生类的构造函数

派生类必须使用基类的构造函数来初始化它的基类部分,每个类控制它自己的成员初始化过程。

要在派生类的构造函数中指明基类的初始化方式,否则基类部分会像数据成员一样执行默认初始化。

派生类的初始化顺序:首先初始化基类部分,然后按照声明的顺序依次初始化派生类的成员。

11、遵循基类的接口

必须明确一点:每个类负责定义各自的接口。要想与类的成员进行交互必须使用该类的接口,即使这个对象是派生类的基类部分也是如此。

因此,派生类对象不能直接初始化基类的成员。派生类应该遵循基类的接口,并且通过调用基类的构造函数来初始化那些从基类中继承而来的成员。

12、理解类和派生类之间的类型转换是理解C++语言面向对象编程的关键所在。基类的指针或引用的静态类型可能与其他动态类型不一致。

13、不存在从基类向派生类的隐式类型转换。编译阶段就已经确定的类型叫做静态类型,运行阶段才能确定的类型叫做动态类型。

14、虚函数

通常情况:如果我们不使用某个函数,则无须为该函数提供定义。但是我们必须为每一个虚函数都提供定义,而不管它是否被用到了,这是因为连编译器也无法确定到底会使用哪一个虚函数。

15、C++的多态性

我们把具有继承关系的多个类型称为多态类型,因为我们能使用这些类型的“多种形式”。引用或者指针的静态类型和动态类型不同这一事实正是C++语言支持多态性的根本所在。

当我们使用基类的指针或引用调用基类中定义的一个函数时,我们并不知道该函数真正作用的对象是什么类型,因为它可能是一个基类对象,也可能是一个派生类对象。如果该函数是虚函数,则直到运行时才会决定到底执行哪个版本,判断的依据是引用或者指针所绑定的基本类型。

另一方面,对于非虚函数的调用在编译时进行绑定。类似的,通过对象进行的函数(虚函数或非虚函数)调用也在编译时绑定。对象类型是确定的,我们无论如何都不可能令对象的动态类型与静态类型不一致。因此,通过对象进行的函数调用,将在编译时绑定到对象所属类中的函数版本上。

16、一个派生类的函数如果覆盖了某个继承而来的虚函数,则它的形参必须与被它覆盖的基类函数完全一致。同样,派生类中虚函数的返回类型也必须与基类函数匹配。该规则存在一个例外,当类的虚函数返回类型是类本身的指针或引用时,上述规则无效。

17、抽象基类

我们通过在函数体的位置(即在声明语句的分号之前)书写 = 0就可以将一个虚函数说明为纯虚函数。其中 = 0 只能出现在类内部的虚函数声明语句处。

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




0 0
原创粉丝点击