【问题标题】:If derived class inherits the private members of a base class, then why not constructors?如果派生类继承了基类的私有成员,那为什么不是构造函数呢?
【发布时间】:2013-02-10 07:46:33
【问题描述】:

我想澄清我对 c# 中这个基本 OOPS 概念的理解。在大多数互联网站点上,我了解到派生类继承基类的私有成员,但它无法访问这些成员。

派生类可以访问公共的、受保护的、内部的和 受保护的基类的内部成员。即使一个派生的 类继承基类的私有成员,它不能访问 那些成员。但是,所有这些私人成员仍然存在于 派生类可以做与基类相同的工作 类本身。例如,假设一个受保护的基类方法 访问私有字段。该字段必须存在于派生的 类,以便继承的基类方法正常工作。

来源:http://msdn.microsoft.com/en-us/library/ms173149.aspx

我的问题是,如果我们认为上面是正确的,那么我们可以说“基类的构造函数是在派生类中继承的,但是派生类只能通过自己的构造函数使用base关键字访问/调用它和this在创建派生类的实例时,构造函数对外部世界不可用"

public class Employee
{
    public int salary;

    public Employee(int annualSalary)
    {
        salary = annualSalary;
    }
}

public class Manager : Employee
{
    public Manager(int annualSalary)
        : base(annualSalary)
    {
        //Add further instructions here.
    }
}

因为要调用基类构造函数,它应该存在于该类内部。也许我的解释是错误的。谁能解释一下?

提前致谢!

【问题讨论】:

  • “派生类可以访问基类的 ... 内部 ... 成员”:只有当两者都在同一个程序集中时,这才是正确的。
  • 问题/问题到底是什么?我的意思是,您知道如何调用基本构造函数以及如何初始化类。那么,如果基本构造函数实际上“存在”,为什么这很重要?
  • 您是在问是否可以通过调用基类构造函数来创建派生类对象?
  • 我认为他希望子类默认调用具有相同签名的基类构造函数,而不是无参数构造函数。但是层次结构可能非常深,您的程序无法确定您是否真的按 'int' 在这种情况下使用与基类中相同的东西。
  • 我知道如何调用构造函数以及它是如何工作的。只是想知道我们是否可以说“基类的构造函数也被继承”......在一次采访中,面试官问我私有成员是否被继承,我说是的,因为我在MSDN上看到过。但后来他问我,同理,构造函数也应该被继承。我没有答案,因为自从进入软件领域以来,我被告知构造函数和析构函数永远不会在派生类中继承!

标签: c# oop inheritance constructor


【解决方案1】:

为了构造Manager,您需要使用基类中的any 构造函数来构造基类,如果只有一个(如本例中)您需要调用它。这并不意味着您必须定义具有相同签名的构造函数。

您也可以这样做:

public Manager() : base(100000)
{
}

public Manager(string name, int salary) : base (salary)
{
     // store name
}

Manager 的构造过程中,您将在堆上分配一个新对象。该对象将要求足够的内存,以便它可以存储在基类 (Employee) 和具体类 (Manager) 中定义的变量。

【讨论】:

  • 对不起,我的问题不是关于如何定义派生类构造函数。我添加的示例只是为了说明我们如何使用 base 关键字调用基类构造函数。我正在寻找的是对“基类构造函数从未在派生类中继承”语句的解释。
【解决方案2】:

这取决于你如何定义“现在”。如果将其定义为“可用的地方”,则基类中的私有成员以及构造函数都是“存在的”。如果您将“存在”定义为“在该特定类中找到”,则两者都不是“存在”。

尝试使用反射。您不会从基类中找到任何私有成员。私有成员是继承的,因此可用,但仍仅在基类中。

构造函数也是如此。

    class A
    {
        private A(int i) { }
        public A() { }
        private void Foo() { }
        public void Bar() { }
    }

    class B : A
    {

    }

    var aProperties = typeof(A).GetMembers(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
    // you won't see Foo in this line, nor any constructors of A
    var bProperties = typeof(B).GetMembers(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public  | BindingFlags.FlattenHierarchy);

最后,你可以说:

  • 基类的所有成员都以某种方式可用于执行。
  • 没有语法可以从继承类(也不能从类外的任何其他地方)调用私有成员
  • 只能从使用base 关键字的构造函数中调用基类的构造函数。 (构造函数总是从层次结构中的每个基类调用。如果未指定,则为默认构造函数。)
  • 只有由类声明(或覆盖)的成员才能真正在该特定类的“内部”找到。使用反射,您可以使用BindingFlags.FlattenHierarchy 来展平基类中的可见成员。私有成员和构造函数只能在声明类中找到。

【讨论】:

  • 您的回答直接与问题中的信息相矛盾,并没有解释问题中给出的解释有什么问题,来自MSDN。
  • 这取决于你如何定义“现在”。如果将其定义为“可用的地方”,则基类中的私有成员以及构造函数都是“存在的”。如果您将“存在”定义为“在该特定类中找到”,则两者都不是“存在”。 MSDN 摘录中没有关于构造函数的内容。我只是说私有成员不像构造函数那样“存在”。
  • 这更有意义。我认为构造函数实际上可以通过私有成员不可访问的方式访问,但不会影响实际代码。
  • 感谢 Stefan 的精彩解释!
【解决方案3】:

"基类的构造函数在派生类中被继承,但是 派生类只能通过自己的构造函数访问/调用它 使用 base 关键字,此构造函数将不可用于 外部世界,同时创建派生类的实例”。

是的,这是正确的。

因为要调用基类的构造函数,所以里面应该存在 那个班级。

就像基地的私人或受保护成员一样,它是“存在的”,但外部无法访问。

【讨论】:

    【解决方案4】:

    如果有一种方法可以让类可以指定对于每个父类构造函数,系统应该推断出具有相同签名和访问权限的子类构造函数的存在,这将是有帮助的,它只做进程字段初始化器并链接到相应的基本构造函数。根据特定要求提供此类功能不太可能导致错误;如果派生类没有指定任何构造函数(而不是仅推断链接到基本无参数构造函数的无参数构造函数),即使这是推理,如果这是一种语言设计特性(添加这样的特性然而,对于现有框架来说,这将是一个坏主意,因为想要公开无参数构造函数但不公开任何参数化构造函数的派生类的作者可能没有包含任何构造函数,期望编译器仅推断无参数构造函数)。

    但是,如果派生类有任何自己的重要构造函数,则子类很可能不打算在不经过其中一个的情况下创建任何对象。假设一个父类只有一个参数化的构造函数并且有人写道:

    class Child : Parent
    {
       Thing blah;
       Child()
       {
          blah = new Thing();
       }
    }
    

    每个创建的Child 都会将blah 设置为一个新事物。现在假设基类的新版本添加了Name 属性,并添加了指定名称的构造函数。如果构造函数是自动继承的,则表示 myChild = new Child("Fred"); 的代码将链接到 Parent 的构造函数,但永远不会将 blah 设置为新的 Thing

    如果一个类可以指定每个实例都应该通过链接到父构造函数然后执行指定的代码块来建立子类不变量来生成,那么安全构造函数“继承”可能成为可能。但是,这样的功能实施起来会有些复杂,而且是否值得付出代价也不清楚。

    【讨论】:

      猜你喜欢
      • 2011-01-02
      • 1970-01-01
      • 2017-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-11-03
      • 2014-11-27
      • 1970-01-01
      • 2020-07-02
      相关资源
      最近更新 更多