基类构造函数总是在您实例化派生类时调用。如果基类有一个默认构造函数,如果你省略对基类构造函数的显式调用,就会调用它。
例如
class Base
{
int x;
int y;
//default constructor
public Base()
{
x = -1;
y = -1;
}
public Base(int x, int y)
{
this.x = x;
this.y = y;
}
}
class Derived
{
public Derived()
{
}
}
这将在创建 Derived 对象时编译并设置派生的实例字段为 -1。
但是,如果您省略默认构造函数,您将收到与您描述的类似的编译错误。现在编译器无法自动生成对基本构造函数的调用。我会知道用哪些参数来调用它
base(x=??,y=??)
通常,您应该多次声明具有相同名称的公共字段/属性,这几乎总是一种强烈的设计气味。
如果基类有一个受保护的、内部的或公共的字段/属性,那么派生类也有(内部有一些奇怪的情况)。对于方法,您可以隐藏 mthod 的基类实现或覆盖它。后者更常见,它要求基本定义是抽象的或虚拟的
例如
//this requires Base to be declared abstract as well
public abstract void AbstractMethod();
public virtual void VirtualMethod(){}
这使您可以在 DErived 类中编写如下
public override void AbstractMethod(){}
public override void VirtualMethod(){}
如果您需要隐藏某个方法,您可以这样做,尽管通常不鼓励这样做(原因见下文)
如果您只是重新声明该方法,编译器会给您一个警告,但您可以使用 new 告诉编译器您实际上想要隐藏该方法,它将如下所示:
public new void SomeHiddenMethod(){}
这如何(可能)对使用该类型的对象产生巨大影响
public void SomeMEthod(Derived d)
{
//this calls the implementation in Derived
d.SomeHiddenMethod();
Base b = d;
//this calls the implementation in Base
b.SomeHiddenMethod();
}
因此,隐藏方法使得推理代码变得非常困难,因为在同一个对象上调用相同的方法可能会产生不同的结果,即使对象在两次调用之间没有改变状态,而仅仅是因为声明的类型变量改变了。
最后一点关于继承你应该避免继承功能,简而言之,这只是因为你需要在两个(不相关的)类中具有相同的功能,你不应该创建一个基类来保存该功能,而是你应该创建第三个类以及该类的注入和实例(或类似方法),在设计未密封的类的公共接口时,您应该多考虑Liskov substitutional principle。