里氏代换原则:
里氏代换原则是面向对象设计的基本原则之一。即任何基类可以出现的地方,子类一定可以出现。
里氏代换原则是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受影响时,基类才能被真正复用,而衍生类也能够在积累的基础上增加新的行为,里氏代换原则是对·开-闭"原则的补充。
- 实现开-闭"原则的关键步骤就是抽象化。
- 在基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
当满足继承的时候,父类肯定存在非私有的成员,子类肯定是得到了父类的这些非私有成员(假设,父类的成员全部是私有的,那么子类没办法从父类继承任何成员,也就不存在继承的额概念了)。既然子类继承了父类的这些非私有成员,那么父类对象也就可以在子类对象中调用这些非私有成员。所以,子类对象可以替换父类对象的位置。
在里氏带环原则下,当需求有变化时,只需继承,而别的东西不会改变。由于里氏代换原则才使得开放封闭称为可能。这样使得子类在父类无需修改就可以扩展。
应用的讨论
- 子类在任何基类使用的地方都必须能够替换它们的基类(is-a)–》里氏代换原则
注意其是public 相当于继承里有默认转换(可以包含设计的类类型和指针类类型可以隐式转换,而内置类型指针不能隐式转换,继承的特征:赋值兼容)
在任何需要基类对象的地方都可以用公有派生类的对象来代替,这条规则称赋值兼容规则。它包括以下情况:
1.**派生类的对象可以赋值给基类的对象,这时是把派生类对象中从对应基类中继承来的隐藏对象赋值给基类对象。**反过来不行,因为派生类的新成员无值可赋。(对象对对象)
2.**可以将一个派生类的对象的地址赋给其基类的指针变量,但只能通过这个指针访问派生类中由基类继承来的隐藏对象,不能访问派生类中的新成员。**同样也不能反过来做。(对象地址对指针)
3.派生类对象可以初始化基类的引用。引用是别名,但这个别名只包含派生类对象中的由基类继承来的隐藏对象。(对象对对象引用)
#include<iostream>
#include<stdlib.h>
using namespace std;
class Person
{
private:
int value;
public:
Person(int x = 0):value(x){}
};
class Student:public Person //公有继承 is 是一个
{
private:
int num;
public:
Student(int x = 0) :num(x), Person(x + 10){}//先构造基类对象,再构造num,构建顺序与列表方式无关
};
void dance(const Person &s)//人能跳舞,学生也能跳舞
{
}
void Study(const Student &s)//只针对学生,人不能学习,即传入限制
{
}
int main()
{
Person se(23);
Student st(10);
Person &ps = st;//引用与指针类似
Person *ps = &st;//类型决定了指针解析能力
se = st;//赋值兼容,其派生类内具有基类的隐藏对象,相当于截断但这里一般称为切片,以区分寄存器
//ps:不能反过来
dance(se);
dance(st);//赋值兼容
//Study(se);//错误,人不一定是学生
Study(st);
return 0;
}