【问题标题】:Does overloading violate Liskov Substitution Principle?重载是否违反里氏替换原则?
【发布时间】:2015-02-15 16:32:18
【问题描述】:

我是 OOP 的新手。最近我读到了 Liskov Substitution Principle。

在下面给出的代码中,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?

如果此代码违反了,那么有人可以给我一个不会违反 Liskov 替换原则的重载示例吗?

我用谷歌搜索了我的查询,但什么也没找到。 :(

提前致谢。

【问题讨论】:

  • Shape 的属性应该作为成员变量封装在 shape 本身中,而不是作为参数传递给区域获取方法。
  • 我实际上可能在这里是少数,但我认为 Liskov 是一件坏事,因为它不必要地限制了你可以做的事情,知道这些东西是如何工作的。见stackoverflow.com/questions/16804817/…。最重要的是,只要您了解您的课程是如何运作的,违反 Liskov 是无关紧要的。
  • 不,我的意思是任何形状的属性。整个概念是您可以将一种形状换成另一种形状,调用具有完全相同签名的方法并接收不会破坏您的代码的有效结果。例如,如果我有一个不同类型的形状向量,它们都继承自一个抽象基类,方法是Area(),我应该能够总结所有形状的总面积,而不管它们是什么形状通过调用每个形状上的 Area() 依次添加到我的总数中。
  • 在 C++ 中,方法参数的逆变被视为完全不同的方法(重载),因此要满足 Liskov 替换原则,您需要所有子类具有相同的方法重载。
  • Liskov-Schmiskov:将π 作为参数传递就是我所说的等待发生的事故! (我确定这只是一个例子,但仍然......)

标签: c++ solid-principles liskov-substitution-principle


【解决方案1】:

LSP

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

答案

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

设计

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

您的代码

在这一点上我必须承认,我并没有真正了解您的代码的目标。有一个类Give_Area,它根据pi 的值计算圆的面积。第二种方法计算一个以Radius 为对角线的正方形?然后是Square 类。如果Validity() 返回 false,那意味着什么?也许是退化的正方形?我的建议是:重新考虑你的设计。问问自己“我想要处理的类和对象是什么?”和“我想要建模的真实世界对象是什么?”

反例

如何违反 LSP 在 Wikipedia(上面的链接)中进行了演示。我将尝试制作第二个示例。假设你有一个类Car 和一个方法drive()。派生类(RacingCarVan、...)可以指定速度、加速度等。当汽车驶入水中(深水、湖泊、大海)时,汽车会破裂并调用下一个车库。现在你派生了一个类AmphibiousVehicle。这个不会在水上破裂,而且车库会毫无用处地被调用。你期待吗?也许是吧。但如果不是,根据进一步的上下文,我会考虑一个类Vehicle,它是Car 的基础。它将有一个方法move()。并且仍然属于Cardrive() 会调用move() 并且可能会调用(再次;-))车库以防遇到麻烦。以此类推。

【讨论】:

  • 首先,感谢您的回答。实际上我只想重载一个方法。我写这段代码只是作为一个例子。这段代码没有任何意义。由于我是 OOP 的新手,我无法确定重载和 LSP 是否矛盾。好的,现在我知道了,重载和 LSP 并不矛盾。现在请给我一个例子,LSP 和重载同时发生吗?提前致谢。只是想熟悉这样的例子。
  • 感谢您的版本。 :) 现在我很清楚了。 :) 很好的答案。 :)
猜你喜欢
  • 2017-05-14
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
相关资源
最近更新 更多