a) 封装:【在c++中的具体表现就是把一个具体的事物封装成类】,并用private、protected、private等关键字修饰类成员,隐藏细节,使代码模快化
b) 继承:【使用现有类的所有功能】,可以分为单一继承和多重继承。继承方式分为public、protected、private。Class默认private继承,struct默认public继承。(一般析构函数都会定义为虚函数,若不然析构时只会调用base的析构函数而不调用derived的析构函数)(封装和继承都是为了【代码重用】)
c) 多态:【允许将子类类型的指针赋值给父类类型的指针】。实现多态的方式有两种,覆盖(重写)和重载。(父类类型作为参数类型,可以接受来自不同子类的参数,【接口重用】,方便多了)
a) public、protect、private
i. 访问分为:被【类成员函数访问】和被【类对象访问】,只有public才能被对象访问
ii. Public:【可以被该类中的函数、子类的函数、以及友元函数访问】+【可以被该类的对象访问】
iii. Protect:【可以被该类的函数、子类的函数、以及友元函数访问】
iv. Private:【可以被该类的函数、友元函数访问】
a) 公有、私有、保护继承
i. public、protect、private
1. 访问分为:被【类成员函数访问】和被【类对象访问】,只有public才能被对象访问
2. Public:【可以被该类中的函数、子类的函数、以及友元函数访问】+【可以被该类的对象访问】
3. Protect:【可以被该类的函数、子类的函数、以及友元函数访问】
4. Private:【可以被该类的函数、友元函数访问】
ii. public、protect、private继承
1. 继承改变的是基类中的成员在作为派生类成员时,成员的封装属性。即派生类继承了基类,基类的成员在派生类中变成了什么类型的成员,所以看继承后,派生类、对象、友元函数对基类成员的访问权限,只要看某种继承后,基类成员在派生类中的类型就行
Public
Protected
Private
Public继承
Public
Protected
不可见
Protect继承
Protected
Protected
不可见
Private继承
Private
Private
不可见
2. 那么对于基类成员对象可见与否,只有公有继承的public成员才对基类和基类的派生类可见(所访问);不论是哪种继承,对于基类的非private成员对于派生类的都是可见的。
b) 虚继承
i. 虚继承是为了在多继承的时候避免引发歧义而使用的(避免菱形继承),如有基类A,A中有成员a,B继承了A,C也继承了A,当D继承B,C时就会有歧义了,2个a。所以要使用虚继承来避免重复拷贝。通俗的讲虚继承是为了节约内存的。
Class A{};
Class B:virtual public A{};
Class C:virtual public A{};
Class D:public B,public C{};
c) 多重继承
a) 实现多态的机制
i. c++中实现多态的方式有两种:覆盖和重载
1. 覆盖是指:子类重新定义父类的虚函数的做法
2. 重载是指:允许存在多个同名函数,而这些函数的参数表,返回值不同
3. 既然重载的函数返回值或参数表不同,那么在编译期时,编译器就能确定调用的是哪个同名函数,那么它的绑定就发生在编译器,是【静态】的;当子类重新定义了父类虚函数后,父类指针根据赋给它的不同子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期是无法确定的(调用的子类的虚函数地址无法给出),因此这样的函数地址是在运行期绑定的,是【动态】的
b) 类成员覆盖/重写/虚函数继承
i. 只有在父类成员方法的前面用virtual关键字修饰,子类才会覆盖父类的方法。从而实现多态
ii. 成员函数的覆盖:子类对父类的成员函数的覆盖,必须函数名称一致,参数一致,返回值一致;成员变量的覆盖:子类覆盖的仅仅是继承来的那个成员变量,并不改变原来父类中的变量值(即:调用父类中涉及到父类变量的函数,父类使用的是父类的值)。
iii. 【构造函数从基类开始构造】,【各个类的同名变量没有形成覆盖】,都是单独的变量。【子类调用就近原则】,如果自己存在相关接口则优先调用,自己没有向父类找,父类没有向祖父找。
c) 类成员的重载
i. 函数名相同,参数表和返回值类型不同,在编译期绑定,是静态的
d) 多态的调用过程
i. 使用对象类型为【基类类型】引用或者指针进行函数调用,首先在基类中查找一个能与待调用函数实参类型相同的函数,如果找不到则调用错误。
ii. 如果找到,看该函数是否是虚函数。如果不是虚函数,【那么即使运行时绑定的是继承类的对象,那么还是调用基类中的函数】;如果是虚函数,而且继承类中有相应的覆盖,那么就会调用指针实际绑定的子类对象的覆盖函数。