过载(overloading)是否违反了 Liskov 替换原则?

5

我是一个OOP的新手。最近我读到了关于Liskov替换原则的内容。

在下面的代码中,Square类继承了Give_Area。假设Square类与正方形相关(例如有效性检查)。Give_Area给出正方形(4个顶点位于圆周上)和圆的面积。因此,如果我给出一个半径,我需要打印出圆和正方形的面积(由放置在该圆周上的顶点组成)。为了获得圆的面积,我使用了一个参数。但是在获取正方形的面积时没有参数。因此,在这里我进行了重载。

#include<iostream>
#include<cmath>
using namespace std;

class Give_Area
{
    public:
    double Radius;

    double Area(double pi)
    {
        return pi*Radius*Radius;
    }

    double Area()
    {
        double temp = sqrt(2.0)*Radius;
        return temp*temp;
    }
};

class Square : public Give_Area
{
    public:
    bool Validity()
    {
        //checking validity
    }
};

int main()
{
    Give_Area* area = new Square();
    area->Radius = 3.0;
    cout<< "Area of Circle: " << area->Area(3.14159) <<endl;
    cout<< "Area of Square: " << area->Area() <<endl;
    return 0;
}

我的问题是...
Is this overloading violating Liskov Substitution Principle?

如果这段代码违反了里氏替换原则,那么是否有人能给我一个不会违反该原则的重载的例子?
我在谷歌上搜索了我的问题,但没有找到任何有用的结果。:(
提前感谢您。

1
Shape的属性应该封装在Shape本身中作为成员变量,而不是作为参数传递给获取面积的方法。 - Matt Coubrough
1
我可能是少数人,但我认为Liskov原则是一件坏事,因为它不必要地限制了你的操作,而且你已经知道这些东西应该如何工作。请参见https://dev59.com/PXLYa4cB1Zd3GeqPaaka#16804908。底线是,只要你_理解_你的类如何工作,违反Liskov原则就是无关紧要的。 - paxdiablo
3
不,我的意思是对于任何形状的属性。整个概念是,您可以将一种形状替换为另一种形状,调用具有完全相同签名的方法,并收到一个有效的结果,而不会损坏您的代码。例如,如果我有一个形状向量,包含不同类型的形状,它们都继承自带有一个名为“Area()”的抽象基类,我应该能够通过依次调用每个形状的Area()并将其添加到我的总面积上,计算出所有形状的总面积,而不管它们是什么形状。 - Matt Coubrough
1
在C++中,方法参数的逆变被视为完全不同的方法(重载),因此为了满足Liskov替换原则,您需要所有子类具有相同的方法重载。 - Matt Coubrough
1
Liskov-Schmiskov:将π作为参数传递是我所说的一个等待发生的意外!(我知道这只是一个例子,但还是...) - AAT
显示剩余3条评论
1个回答

3

LSP原则

Liskov替换原则(或LSP)是关于抽象的。想象一个类Shape和两个派生自Shape的类SquareRectangle。现在,Shape有一个(虚拟的)方法getArea()。您期望它返回由(具体,实例化的!)形状覆盖的区域,而不管它实际上是什么类型。因此,如果在Shape实例上调用getArea(),则无论它是矩形、正方形还是其他任何形状,您都不关心。

答案

没有重载,甚至不需要像LSP这样的东西,即答案是否定的,重载和LSP并不矛盾。

设计

另一方面,正如paxdiablo指出的那样,应用LSP取决于设计。就上面的例子而言,这意味着也许由于某种原因,您实际上确实关心是否有矩形。好吧,在这种情况下,LSP表示您应该考虑您的设计。

您的代码

在这一点上,我必须承认,我真的不知道您的代码的目标在哪里。有一个类Give_Area,它根据pi的值计算圆的面积。第二个方法计算一个以Radius为对角线的正方形?如果Validity()返回false,那会意味着什么呢?可能是一个退化的正方形吗?我的建议是:重新考虑您的设计。问问自己“我想要处理哪些类和对象?”和“我想要模拟哪些真实世界的对象?”

反例

在维基百科上演示了如何违反LSP(上面的链接)。我将尝试举一个第二个例子。假设您有一个类Car和一个方法drive()。 派生类(RacingCarVan,...)可以指定速度、加速度等。 当汽车开到水里(深水、湖泊、海洋)时,汽车将损坏并呼叫下一个修车厂。 现在你派生了一个类AmphibiousVehicle。 这个类不会在水中损坏,并且无法使用修车厂。 你期望了吗?也许是。但如果没有,根据进一步的上下文,我会考虑一个类Vehicle,它是Car的基础。 它将有一个方法move()。而属于Cardrive()仍然会调用move(),并在出现问题时可能会再次调用(;-))修车厂。以此类推。

首先,感谢您的回答。实际上我只是想重载一个方法。我写这段代码只是作为一个例子。这段代码没有任何意义。由于我是OOP的新手,我无法确定重载和LSP是否相互矛盾。现在我知道了,重载和LSP并不相互矛盾。现在,您能否给我一个同时出现LSP和重载的例子呢?提前感谢您。我只是想熟悉这样的例子。 - Mukit09
感谢您的编辑。 :) 现在我明白了。 :) 很棒的答案。 :) - Mukit09

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接