C++ OOP

来源:互联网 发布:国家外汇管理局 知乎 编辑:程序博客网 时间:2024/06/15 09:17

OOP object-oriented programming 面向对象程序设计

1、动态绑定
两个条件:
①使用基类的引用或指针
②调用一个虚函数

2、派生类构造函数
尽管在派生类对象中含有从基类继承的成员,但派生类并不能直接初始化这些成员,需要使用基类的构造函数来初始化它的基类部分。
所以可以思考:构造函数不能是虚函数,因为构造函数为虚函数的话,派生类在创建对象时,则只会初始化派生类的成员,而不会初始化基类成员

3、继承与静态成员
无论派生多少个派生类,静态成员只存在唯一实例。
静态成员遵循通用的访问控制规则,假设某静态成员可访问,则既可以通过基类,也可以通过派生类使用它。

4、派生类的声明
声明包含类名,但不包括它的派生列表。
class Bulk_quote:public Quote; //错误
class Bulk_quote; //正确

5、防止一个类被继承
使用final

class NoDerived final{
……
};

6、类型转换与继承
①可以将基类的指针或引用绑定到派生类对象上

②不存在从基类向派生类的隐式类型转换
因为编译器在编译时无法确定某个特定的转换在运行时是否安全,这是因为编译器只能通过检查指针或者引用的静态类型来推断该转换是否合法。
如果我们已知某个基类向派生类转换是安全的,则我们可以使用static_cast来强制覆盖掉编译器的检查工作。

7 虚函数
OOP的核心思想是多态性,源自希腊语,其含义是“多种形式”。
我们把具有继承关系的多个类型成为多态类型,因为我们能使用这些类型的“多种形式”而无需在意他们的差异。
引用或指针的静态类型与动态类型不同正是C++语言支持多态性的根本所在。

编译时绑定的情况(非动态绑定)
①对非虚函数的调用,无论调用它的是指针还是引用还是类对象,都会在编译时候绑定
②通过类对象进行的函数调用,无论调用的函数是虚函数还是非虚函数

8、派生类中的虚函数
派生类中覆盖某个虚函数时候,可以使用virtual再一次指明该函数性质,然而这么做并非必须,因为一旦某个函数声明为虚函数,则在所有派生类它都是虚函数。

覆盖继承而来的虚函数,虚函数的形参类型必须与基类的一致。
同样,派生类中虚函数返回类型也应该与基类函数相匹配。这里存在一个例外,当类的虚函数返回类型是类本身的指针或引用时候,可以用派生类的指针或引用作为返回类型。

9、override的含义
派生类定义一个与基类中虚函数名字相同但形参列表不同的函数,这是合法的,但这个函数并未覆盖基类中的虚函数,而是新的函数。
我们可能希望派生类中能覆盖掉基类中的虚函数,但由于形参列表搞错了导致并未覆盖,此时我们可以使用override来“上一层保险”。
override是用来覆盖已存在的虚函数!记住覆盖的是虚函数,基类中非虚函数在派生类中重写再加个override是出错的。

10、final
final阻止类的进一步派生和虚函数的进一步重载。
两个作用:
①阻止类的派生
②阻止虚函数的进一步覆盖。(是阻止虚函数!)

11、纯虚函数
虚函数的定义形式:virtual {method body}
纯虚函数的定义形式:virtual { } = 0;

在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时候要求前期bind,然而虚函数却是动态绑定(run-time bind),而且被两者修饰的函数生命周期(life recycle)也不一样。

抽象基类:含有纯虚函数。
抽象基类负责定义接口,我们不能创建一个抽象基类的对象。

12、访问控制与继承

一个类有3中用户:
①普通用户 public
②类的实现者 public、protected、private
③派生类及其友元 public、protected

对于 “protected修饰的成员” 来说来说,有3种意思:
①对普通用户不可访问
②对于派生类的成员及其友元是可以访问的
其中第②点具体一点,是派生类的成员或者友元只能通过“派生类对象”来访问基类的受保护成员。派生类对于一个基类对象的受保护成员没有任何访问特权

class Base{protected:    int protectedMem;};Class Derive:public Base{    friend void fun(Derive& iderive); // (1)    friend void fun(Base& ibase);    // (2)}void fun(Base& ibase){    cout<<protectedMem;               //(3)    cout<<ibase.protectedMem;        // (4)}

如上,由于Derive是public继承Base,所以Base中的protectedMem在Derive是可以访问的。
在(1)中因为传入的是Derive对象,我们可以通过其派生类对象访问一个新的Derive对象的protectedMem;
(2)函数的代码中,(3)是没错的,因为this指针指向的protectedMem是继承Base的,通过继承关系我们可以知道自身的protectedMem在Derive类中依然是protected的。
但是(4)式子中,是新传入的ibase对象,我们无权访问。fun并不是Base类的友元函数,所以是以普通用户的身份来使用Base对象的,所以只能访问Base对象中public部分的成员。

13、公有、私有和受保护继承

用自己的话说,比如D继承B后,

那么它改变了什么?
D继承B,
如果是公有继承,那么B中的访问属性不变照搬到D中。
如果是私有继承,那么B中的访问属性全变成私有属性搬到D中。
如果是受保护继承,那么B中public属性的成员改为私有属性搬到D中,其他照搬到D中。

然后我们可以看看这个D,作为类的普通用户你能访问什么?
其中派生类及其普通用户除了基类原本私有属性成员不可访问,其他都可以。

14、派生类向基类转换的可访问性

对于代码中某个给定地方来说,如果基类的公有成员可访问,则派生类向基类的类型转换可以访问。

思考:D分别以公有、私有、受保护继承B,
那么用户代码、D的成员函数和友元、D的派生类的成员和友元 可以么?