【发布时间】:2011-04-05 06:56:06
【问题描述】:
这是来自“Exceptional C++”第 24 条,解决方案,页面底部的第一个项目符号的片段:
切勿使用公共继承来实现“IS-ALMOST-A”。我见过一些程序员,甚至是经验丰富的程序员,从基类公开继承,并以保留基类语义的方式实现“大多数”被覆盖的虚函数。换句话说,在某些情况下,将 Derived 对象用作 Base 的行为方式与合理的 Base 客户端所期望的方式不同。 Robert Martin 经常引用的一个例子是从 Rectangle 类继承 Square 类的通常被误导的想法,“因为正方形就是矩形”。这在数学中可能是正确的,但在课堂上不一定是正确的。例如,假设 Rectangle 类有一个虚拟 SetWidth(int) 函数。然后 Square 设置宽度的实现也会自然地设置高度,以便对象保持正方形。然而,系统中的其他地方很可能存在与 Rectangle 对象进行多态工作的代码,并且不会期望改变宽度也会改变高度。毕竟,一般的矩形不是这样的!这是违反 LSP 的公共继承的一个很好的例子,因为派生类不提供与基类相同的语义。它违反了公共继承的关键戒律:“要求不多,承诺也不少。”
我试着检查了一下,我写道:
// Square.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
using namespace std;
class Rectangle
{
private:
unsigned width_;
unsigned height_;
public:
Rectangle(const unsigned width, const unsigned height):width_(width),height_(height)
{/*Empty body*/ }
unsigned GetWidth()const
{
return width_;
}
unsigned GetHeight()const
{
return height_;
}
virtual void SetWidth(const unsigned width)
{
width_ = width;
}
void SetHeight(const unsigned height)
{
height_ = height;
}
virtual ~Rectangle()
{
cout << "~Rectangle()" << '\n';
};
};
class Square : public Rectangle
{
using Rectangle::SetWidth;
public:
Square(const unsigned width):Rectangle(width,width)
{
}
void SetWidth(const unsigned width)
{
SetWidth(width);
SetHeight(width);
}
~Square()
{
cout << "~Sqare()" << '\n';
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Rectangle** a = static_cast<Rectangle**>(operator new (sizeof(Rectangle) * 2));
a[0] = new Rectangle(10,10);
a[1] = new Square(5);
Rectangle* r = a[0];
cout << r->GetHeight() << "\t" << r->GetWidth() << '\n';
r = a[1];
cout << r->GetHeight() << "\t" << r->GetWidth() << '\n';
r = a[0];
r->SetWidth(20);//here I'm setting just width for a Rectangle
cout << r->GetHeight() << "\t" << r->GetWidth() << '\n';
delete a[1];
delete a;
return 0;
}
至于我从 Rectangle 继承 Square 按预期工作。那么我在哪里犯了错误并且不明白这个项目符号中所说的内容?
谢谢
【问题讨论】:
标签: c++ inheritance