今天学习后对C++中类继承关系最深的印象就是各家自扫门前雪,类只负责控制管理自己的data members的生命周期,下面记录对一些对OOP的理解
成员访问说明符:public,private,protected(友元/派生类)
Protected:派生类只能访问它自己基类部分的protected成员。
改变成员的访问性:public using Base::member1; //前提是D可以访问member1
动态绑定:调用虚函数时发生,表现为基类的指针 or 引用可以指向 or 绑定到派生类对象。
类型转换:基类Base的指针和引用可以指向或绑定到派生类对象。本质是Slice down,即忽略派生类独有的部分,只关注Base包含的成员
Base指针/引用的静态编译类型仍然为Base,编译器无法调用派生类独有的非虚函数
基类类型和派生类类型之间无法转换
虚函数:虚函数隐式地被继承给派生类,可用override显式覆盖(避免覆盖的函数并非虚函数),可用final显式防止继承
通过指针/引用调用时,虚函数的调用运行时才被解析
派生类中虚函数的返回类型与参数类型必须与基类匹配(除非返回*this)
回避虚函数:BasePtr->Base::vf(); //显式调用Base版本的vf虚函数;可避免无线递归
抽象基类:含纯虚函数(void vf() const = 0;)的类,类内无法为纯虚函数定义函数体。
派生列表访问说明符:目的时控制用户代码,而非派生类成员 or 友元,因此派生类的成员/友元永远可以使用D(派生类)到B(基类)的转换
- public:只有公有继承时,用户代码才能用D到B的转换
- protected:用户代码不可用,D的派生类及D的友元可用D's D向B的转换
- private:D的派生类及D的友元无法使用D's D向B的转换
举个例子吧
Class Father{...};
Class Children1 : public Father {...};
Class Children2 : protected Father {...};
Class Children3 : private Father {...};
Class c_C1 : public Children1 {...};
Class c_c2 : public Children2 {...};
Class c_c3 : public Children3 {...};
int main()
{
//用户代码块
Father *p;
Children1 c1;
Children2 c2;
Children3 c3;
p = &c1; //合法,因为c1公有继承了Father
p = &c2; //非法,因为用户代码无法使用从protected derived 到 base 的转换
p = &c3; //非法,理由同上
//假设以上7个类都有成员函数member(Father &f) {f=*this;}
//则只有c_c3中的member函数不合法,因为其直接基类Children3 private继承了Father,
//因此c_c3中的member函数无法完成从 *(&c_c3)到&father的转换
}
名字冲突:派生类隐藏基类的同名函数。因此重载虚函数时,注意参数列表完全一样,否则派生类将会隐藏虚函数并定义一个同名的新成员函数。
- 由里到外匹配名字直至继承链顶端
- 匹配到名字则进行类型检查,不匹配则报错
- 虚函数则运行时确定
- 非虚函数则直接调用