在派生类中隐藏基类的公共属性
本文关键字:属性 基类 隐藏 派生 | 更新日期: 2023-09-27 18:17:19
我想知道我们是否可以在Derived Class
中隐藏Base Class
的public
属性。
我有以下示例问题语句用于计算不同形状的Area
-
abstract class Shape
{
public abstract float Area();
}
class Circle : Shape
{
private const float PI = 3.14f;
public float Radius { get; set; }
public float Diameter { get { return this.Radius * 2; } }
public Circle() { }
public Circle(float radius)
{
this.Radius = radius;
}
public override float Area()
{
return PI * this.Radius * this.Radius;
}
}
class Triangle : Shape
{
public float Base { get; set; }
public float Height { get; set; }
public Triangle() { }
public Triangle(float @base, float height)
{
this.Base = @base;
this.Height = height;
}
public override float Area()
{
return 0.5f * this.Base * this.Height;
}
}
class Rectangle : Shape
{
public float Height { get; set; }
public float Width { get; set; }
public Rectangle() { }
public Rectangle(float height, float width)
{
this.Height = height;
this.Width = width;
}
public override float Area()
{
return Height * Width;
}
}
class Square : Rectangle
{
public float _side;
public float Side
{
get { return _side; }
private set
{
_side = value;
this.Height = value;
this.Width = value;
}
}
// These properties are no more required
// so, trying to hide them using new keyword
private new float Height { get; set; }
private new float Width { get; set; }
public Square() : base() { }
public Square(float side)
: base(side, side)
{
this.Side = side;
}
}
现在有趣的是在Square
类中Height
&Width
属性不再需要(因为它被Side
属性所取代)暴露给外部世界,所以我使用new
关键字来隐藏它们。但是它不工作,用户现在可以设置Height
和Width
-
class Program
{
static void Main(string[] args)
{
Shape s = null;
// Height & Width properties are still accessible :(
s = new Square() { Width = 1.5f, Height = 2.5f };
Console.WriteLine("Area of shape {0}", s.Area());
}
}
有谁知道在c#中隐藏派生类的属性是不需要的吗?
重要提示:有人可能会指出Shape -> Rectangle -> Square
不是一个合适的继承设计。但我想保持这种方式,因为我不想在Square
类中再次编写"不精确"但类似的代码(注意:Square
类使用其基类Rectangle
的Area
方法。在现实世界中,对于这种类型的继承,方法逻辑可能会更复杂)
任何子类型基本上仍然能够被视为基类型的实例。如果有人将变量作为基类型,则当然不能隐藏成员。你最多能做的就是在使用派生类型时让他们非常讨厌使用,例如:
[Obsolete, Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new float Width { get { return base.Width;} }
您也可以对override
做类似的事情,如果访问器(特别是set
)使用不当,甚至可能是throw
。
然而,听起来更像是您应该更改继承模型,使永远不希望尝试删除成员。
我仍然认为Shape -> Rectangle -> Square
是所有问题的根源。继承不仅仅是关于代码重用。如果你有类似的代码来计算面积,你可以组成逻辑:也就是说,将面积计算的逻辑外部化到一个单独的类中,并在Square和Rectangle中重用。
回到你最初的问题,你需要在子类中隐藏基类中的属性,这是一个很大的设计气味——语言设计者绝对不希望有这样的特性。
(您可能还想阅读有关Liskov替代原理)
一想到,我想我会声明Rectangle
的Height
和Width
为虚拟的,并在Square
类中覆盖它,而不是试图隐藏它们:
class Square : Rectangle
{
public float Side{get;set;}
public override float Height { get{return Side;}; set{Side =value;} }
public override float Width {get{return Side;}; set{Side =value;} }
public Square() : base() { }
public Square(float side)
{
this.Side = side;
}
}
从矩形继承正方形的优点是什么?也许你需要一个新的类,比如:
abstract class Square<TFigure> where TFigure : Shape
{
public float Side {set; get;}
protected Square(TFigure stereotype)
{
Side = GetStereotypeSide(stereotype)
}
public abstract float GetStereotypeSide(TFigure stereotype);
}
那么你的正方形可以像下面这样
class RectangleSquare: Square<Rectangle>
{
public RectangleSquare() : base (new Rectangle(){Height = 1, Width = 2})
{
}
public override float GetStereotypeSide(Rectangle stereotype)
{
return stereotype.Height*stereotype.Width;
}
}
如果您仍然需要Square和Shape的公共对象,则可以定义
interface IGeometry{
}
,然后将接口继承添加到两个类
class Shape : IGeometry
....
和
abstract class Square<TFigure> : IGeometry where TFigure : Shape
我返回@aquaraga。如果您希望隐藏基类中的公共内容,则派生是不正确的。组合是一个更好的解决方案,在必要时委托给另一个(基)类。