c++primer第十五章面向对象设计小结-15

第十五章------面向对象设计

1、面向对象程序设计(object-oriented programming)的核心思想是数据抽象、继承和动态绑定。数据抽象技术使实现和接口分离,继承可以很快捷方便的定义相似的关系类,动态绑定(因为基类指针和引用可以指向或绑定到派生类的对象,所以只有程序运行到调用的函数处才会因为参数类型不同而决定到底指向的是基类还是派生类,编译时就知道的类型,比如内置数据类型,那是属于静态绑定),可以使得程序以一种统一的方式调用函数。

2、.C++ 中的函数调用默认不使用动态绑定。要触发动态绑定,满足两个条件:第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;第二,必须通过基类类型的引用或指针进行函数调用。要理解这一要求,需要理解在使用继承层次中某一类型的对象的引用或指针时会发生什么。

3、派生类的构造函数必须重新写过,不能继承。(因为毕竟两个类的类名都不一样,不可能构造函数继承)只继承其他的成员函数和成员变量。派生类可以覆盖基类的虚函数,但是也可以选择不覆盖(即直接使用父类的函数版本),基类的静态成员:如果基类有一个静态成员,那么基类和所有派生类都共同拥有这仅有的一个静态成员。所以只有构造函数和静态成员函数不能为virtual函数如果子类不显式调用父类的构造函数,编译器会自动调用父类的【无参构造函数】;

4、 继承构造函数(Inheriting constructors)

(1) C++11 才支持;

(2) 实质是编译器自动生成代码,通过调用父类构造函数来实现,不是真正意义上的【继承】,仅仅是为了减少代码书写量(参考 《C++ Primer》)

5、继承的权限:
    1.如果是公用继承,基类成员保持自己的访问级别:基类的 public 成员为派生类的 public 成员,基类的 protected 成员为派生类的 protected成员。
    2.如果是受保护继承,基类的 public 和 protected 成员在派生类中为protected 成员。
    3.如果是私有继承,基类的的所有成员在派生类中为 private 成员。

6、接口继承与实现继承
    1.public 派生类继承基类的接口,它具有与基类相同的接口。设计良好的类层次中,public 派生类的对象可以用在任何需要基类对象的地方。
    2.使用 private 或 protected 派生的类不继承基类的接口,相反,这些派生通常被称为实现继承。派生类在实现中使用被继承但继承基类的部分并未成为其接口的一部分

7、友元关系不能继承。
8、如果基类定义 static 成员,则整个继承层次中只有一个这样的成员。
9、派生类构造函数通过将基类包含在构造函数初始化列表中来间接初始化继承成员。
10、一个类只能初始化自己的直接基类。
11、在函数形参表后面写上 = 0 以指定纯虚函数:
    将函数定义为纯虚能够说明,该函数为后代类型提供了可以覆盖的接口,但是这个类中的版本决不会调用。重要的是,用户将不能创建 Disc_item 类型的对象。
12、将派生类对象复制到基类对象时,派生类对象多出的部分将被切掉

13、C++11 标准允许派生类显示地注明它将使用哪个成员函数改写基类的虚函数,具体措施是在该函数的形参列表之后增加一个 override 关键字。
14、在C++语言中,当我们使用基类的引用或指针调用一个虚函数时将发生动态绑定。
15、基类通常都应该定义一个虚析构函数,即使该函数不执行任何实际操作也是如此。
16、任何构造函数以外的非静态函数都可以是虚函数。关键字 virtual 只能出现在类内部的生命语句之前而不能用于类外部的函数定义。如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数。
17、成员函数如果没有被声明成虚函数,则其解析过程发生在编译时而非运行时。
18、C++11 新标准提供了一种防止继承发生的方法,即在类名后跟一个关键字 final 。
19、理解基类和派生类之间的类型转换是理解C++语言面向对象编程的关键所在。当我们用一个派生类对象为一个基类对象初始化或赋值时,只有该派生类对象中的基类部分会被拷贝、移动或赋值,它的派生类部分将被忽略掉。要理解在具有继承关系的类之间发生的类型转换,有三点非常重要:
    ① 从派生类向基类的类型转换只对指针或引用类型有效;
    ② 基类向派生类不存在隐式类型转换;
    ③ 和任何其他成员一样,派生类向基类的类型转换也可能会由于访问受限而变得不可行。
    (尽管自动类型转换只对指针或引用类型有效,但是继承体系中的大多数类仍然(显示或隐式地)定义了拷贝控制成员。因此,我们通常能够将一个派生类对象拷贝、移动或赋值给一个基类对象)
20、动态绑定只有当我们通过指针或引用调用虚函数时才会发生。
21、基类中的虚函数在派生类中隐含地也是一个虚函数。当派生类覆盖了某个虚函数时,该函数在基类中的形参必须与派生类中的形参严格匹配。
22、如果我们希望对虚函数的调用不要进行动态绑定,而是强迫其执行虚函数的某个特定版本。使用作用于运算符可以实现这一目的。通常情况下,只有成员函数(或友元)中的代码需要使用作用域运算符来回避虚函数的机制。
23、含有(或者未经覆盖直接继承)纯虚函数的类时抽象基类(abstract base class)。我们不能创建抽象基类的对象。
24、派生类的成员或友元只能通过派生类对象来访问基类的受保护成员。
25、对于代码中的某个给定节点来说,如果基类的公有成员是可访问的,则派生类向基类的类型转换也是可访问的;反之则不行。
26、不能继承友元关系;每个类负责控制各自成员的访问权限,控制自己成员初始化。
27、派生类只能为那些它可以访问的名字提供 using 声明。
28、人们常常有一种错觉,认为在使用 struct 关键字和 class 关键字定义的类之间还有更深层次的差别。事实上,唯一的差别就是默认成员访问说明符及默认派生访问说明符;除此之外,再无其他不同之处。
29、派生类的成员将隐藏同名的基类成员。我们可以通过作用于运算符来使用一个被隐藏的基类成员。(除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义在基类中的名字。)
30、和其他作用域一样,如果派生类(即内层作用域)的成员与基类(即外层作用域)的某个成员同名,则派生类将在其作用域内隐藏该基类的成员。即使派生类成员和基类成员的形参列表不一样,基类成员也仍然会被隐藏掉。
31、如果基类的析构函数不是虚函数,则 delete 一个指向派生类的基类指针将产生未定义的行为。(动态绑定析构函数)
32、如果一个类定义了析构函数,即使它通过 =default 的形式使用了合成的版本,编译器也不会为这个类合成移动操作。
33、当派生类定义了拷贝或移动操作时,该操作负责拷贝或移动包括基类部分成员在内的整个对象。
34、在默认情况下,基类默认构造函数初始化派生类对象的基类部分。如果我们想拷贝(或移动)基类部分,则必须在派生类的构造函数初始值列表中显示地使用基类的拷贝(或移动)构造函数。
35、与拷贝和移动构造函数一样,派生类的赋值运算符也必须显示地为其基类部分赋值。
36、如果构造函数或析构函数调用了某个虚函数,则我们应该执行与构造函数或析构函数所属类型相对应的虚函数版本。
37、如果基类含有几个构造函数,则除了两个例外情况,大多数时候派生类会继承所有这些构造函数:
    ① 如果派生类定义的构造函数与基类的构造函数具有相同的参数列表,则该构造函数将不会被继承。
    ② 默认、拷贝和移动构造函数不会被继承。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章