C# 类继承

7

你好。我有以下的类:

public class Ship
{
    public enum ValidShips
    {
        Minesweeper,
        Cruiser,
        Destroyer,
        Submarine,
        AircraftCarrier
    }

    public enum ShipOrientation
    {
        North,
        East,
        South,
        West
    }

    public enum ShipStatus
    {
        Floating,
        Destroyed
    }

    public ValidShips shipType { get; set; }

    public ShipUnit[] shipUnit { get; set; }

    public ShipOrientation shipOrientation { get; set; }

    public ShipStatus shipStatus { get; set; }

    public Ship(ValidShips ShipType, int unitLength)
    {
        shipStatus = ShipStatus.Floating;

        shipType = ShipType;

        shipUnit = new ShipUnit[unitLength];

        for (int i = 0; i < unitLength; i++)
        {
            shipUnit[i] = new ShipUnit();
        }
    }
}

我希望能像这样继承这个类:
public class ShipPlacementArray : Ship
{

}

这很有道理。

我想知道如何删除基类的某些功能?

例如:

    public ShipUnit[] shipUnit { get; set; } // from base class

i would like it to be:

    public ShipUnit[][] shipUnit { get; set; } // in the derived class

我的问题是如何实现隐藏基类shipUnit的代码?

否则,我将在派生类中有两个shipUnit实现。

感谢您的时间。

ShipPlacementArray仅处理一艘船。但该数组反映了可以放置船只的方向。


哇,看起来好像有一些混蛋来到这里给大家的答案投了负票。 - AaronLS
11个回答

15
我想知道的是如何删除基类的某些功能?您不需要这样做,这不是继承的目的。继承的目的是继承基类的所有功能并添加/更改内容。它用于“is-a”关系,例如,“车是一种交通工具”。
您似乎希望ShipPlacementArray成为多个Ship对象的包装器或容器。这似乎不是应该使用继承的情况。
问自己一个问题:“ShipPlacementArray是一种Ship吗?”

ShipPlacementArray 不是一艘船,但它与 ship 类共享大量的数据/相似之处。这就是为什么我考虑从 ship 类继承的原因。 - iTEgg
在这种情况下,您可以创建一个实现常见功能的类,并从中派生ShipShipPlacementArray。但是,如果您真的正在创建战舰游戏(正如您的代码所示),我想不出两者有什么值得的共同之处。 - Thomas
Thomas:我理解你说的第一部分,但后面的部分我不确定是否理解。ShipPlacementArray是一个容器,用于在网格上分配船只位置时存储可用的船只放置位置。 - iTEgg
没错。它是一个“船只容器”,而不是一艘“船只”。你在ShipPlacementArray中还需要哪些Ship的功能呢?(一些恰好具有相同名称的属性不算,因为它们具有不同的类型!) - Thomas
Thomas:它是船只的一个容器,用于存储船只在网格上可以停靠的位置。 - iTEgg
同意@Thomas的观点 - ShipPlacementArray不是Ship的一种。任何行为与基类不符的对象,都不应该继承自该类。你为什么想让ShipPlacementArray继承自ShipShip有什么功能,ShipPlacementArray也需要实现吗? - Tom W

7

根据我的经验,每当我想在继承类中删除一个属性时,我的类设计就有缺陷。解决这个问题的方法之一是创建一个没有ShipUnit属性的新基类,然后分别为具体的Ship类型和具体的ShipPlacementArray类型继承该基类两次。在两个子类中,您可以按照需要实现ShipUnit。


是的,作为一个初学者,我还不能一次性完全思考出来。我认为你提供的信息解决了我遇到的问题。只需将数据分成有用的单元即可,这在某种程度上我已经做到了,但是你的建议为我的设计提供了下一步的清晰方向。谢谢。 - iTEgg
@ikurtz - 继承应始终遵循“是一个”关系。你能说“ShipPlacementArray是一艘船”,并且这样说有意义吗(就像“圆是形状”一样)?如果不能,那么就要重新设计了 :) - Paolo

2
您无法在派生类中使基类成员消失。 在某些情况下,您可以通过在派生类中使用new关键字来屏蔽隐藏基成员,但用户始终可以将对象转换回基类(base)instance_of_derived并访问基类的成员。
因此,例如,在您的派生类中可以这样做:
public new ShipUnit[][] shipUnit { get; set; }

但是我可以做到:

((Ship)ShipPlacementArray_instance).shipUnit

这将引用原始的shipUnit。因此,您可以“隐藏”成员,但无法禁用其功能或可访问性。


2

使用 C# 的 new 修饰符,您可以隐藏来自基类成员的继承成员。请参考此页面了解更多信息。


1
除了其他出色的答案,我想说你可能会发现封装更好。通常我最初会认为我想从一个类中继承,但后来发现我真正想要的是将其封装起来。您只需在私有字段中声明原始类的新实例即可完成此操作。然后,您创建公共属性和函数,仅像下面一样调用原始类,从而使您对所公开的内容有更好的控制。这也是规避继承缺点的一种方法,如增加的复杂性以及无法执行多重继承(出于良好的原因):
class SomeNew
{
  private SomeOld someOld = new SomeOld();//could have done this in constructor instead

  public DoSomething()
  {
    someOld.DoSomething();
  }
}

1

我不知道这是一个刻意编造的例子还是一个实际问题。但是,我认为在这种情况下继承并不是所期望的。你有Ship和ShipPlacementArray。结尾的“Array”让它听起来更像是一个数组数据类型。因此,如果去掉它,你就得到了ShipPlacement。

对我来说,这听起来像是某个位置,所以也许它应该是Ship类的成员?


1
“优先使用对象组合而非类继承” - 如果您正在寻找基类的新行为,那么似乎您不想继承,因为它们是不同类型的。 也许Ship和ShipPlacementArray应该继承一个共同的接口,但肯定不是从一个共同的基类继承。无论何时需要使用任一对象,都可以使用接口 - 但在需要使用ShipUnit矩阵的地方,您将明确使用ShipPlacementArray类型。

0

您可以使用new关键字,像这样:

public new ShipUnit[][] shipUnit { get; set; }

我投了反对票,因为new是一种隐藏基类实现并开始新继承层次结构的方法,但这种解决方案并没有真正解决所提出的问题 - 它最多只能修复一些症状。 - Daniel Brückner
1
@Daniel Brückner,问题是“我的问题是如何实现完全隐藏基类shipUnit的代码?”,而不是“我该如何修复这个设计?” - Max Toro
是的和不是的。它回答了提问者所问的问题,但并没有给他(真正)需要的信息。 - Daniel Brückner
@Daniel Brückner,然而,对一个正确的答案进行负评是完全没有必要的。 - Max Toro

0
你可以使用"new"运算符。例如:
public new ShipUnit[][] shipUnit { get; set; } // in the derived class

1
我投了反对票,因为new是一种隐藏基类实现并开始新继承层次结构的方法,但这种解决方案并没有真正解决所提出的问题 - 它最多只能修复一些症状。 - Daniel Brückner

0

我不完全理解你想用继承来建模的意图,但我相当确定这是错误的工具。我猜测聚合或组合是你需要的。


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