里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現;並且完全察覺不出父類對象和子類對象的區別。
里氏代換原則是一個規範性原則,它是繼承複用的基石。只有按照這個規範來具體化抽象,才能保證這個系統正常運行!
代碼定義:
// 如果D派生自B;B、D指向同一對象;則test_func(b) 與 test_func(d)效果完全相同
class B
{
}
class D : public B
{
}
client:
D* d = new D();
B* b = d;
test_func(b)
test_func(d)
要實現這個原則,需要滿足一下條件
①public繼承
②不要覆蓋、重載基類中的任何函數。
③子類必須具有父類的所有性質。
下面看看幾個違背里氏代換規則的例子:
一、鳥與企鵝
在生物學上,企鵝屬於鳥類。所以你一定認爲企鵝派生自鳥類沒有問題。但注意,這裏是軟件學!不是生物學!衆所周知,鳥是可以飛的,那麼鳥類中肯定有一個fly函數。若企鵝派生自鳥類,那麼根據里氏替換原則,企鵝具有父類所有的性質。換言之,就是企鵝也會飛了。會飛的企鵝,那還是企鵝嗎?!
這個例子告訴我們,在繼承時,一定要遵守里氏替換原則,使子類具有父類的所有性質!
二、覆蓋基類函數
class A{
public int func1(int a, int b){
return a-b;
}
}
class B extends A{
public int func1(int a, int b){
return a+b;
}
}
public class Client{
public static void main(String[] args){
B b = new B();
A a = b;
System.out.println("100-50="+a.func1(100, 50));
System.out.println("100-80="+b.func1(100, 50));
}
}
這裏會發現,同樣是B的對象,同樣的運算,兩個結果卻截然不同。
所以,若有需求,則用虛函數重寫基類函數,但不能重載或覆蓋基類函數。