C# 继承和默认构造函数

Posted

技术标签:

【中文标题】C# 继承和默认构造函数【英文标题】:C# inheritance and default constructors 【发布时间】:2015-07-09 16:33:07 【问题描述】:

假设有一个基类A 和一个派生自A 的类B。 然后,我们知道类A 的构造函数永远不会被类B 继承。但是,当创建B 的新对象时,在调用B 类的默认/自定义构造函数之前调用类A 的默认构造函数。可能这样做的目的是A类的字段需要初始化为默认值。

现在,假设 A 类定义了一个自定义构造函数。这意味着类A 的默认构造函数被编译器静默删除。现在,在创建类B 的新实例时,在调用类B 的构造函数之前会自动调用类A 的哪个构造函数? (在这种情况下,A 类字段如何初始化?)

【问题讨论】:

我没有意识到 OOPS 是面向对象编程 S*。不建议编辑,因为我喜欢将其视为"oops"。 @PeterMortensen 这应该是什么完全相同的副本? 已经回滚了删除 c# 标签的编辑,并且为了清楚起见还编辑了主题行。这绝对是一个特定于语言的问题。 【参考方案1】:

现在,在创建类 B 的新实例时,在调用类 B 构造函数之前会自动调用类 A 的哪个构造函数?

基本上,代码将无法编译。每个构造函数都必须隐式或显式链接到另一个构造函数。它链接的构造函数可以在同一个类(this)或基类(base)中。

这样的构造函数:

public B() 

是隐含的:

public B() : base() 

...如果您根本没有指定构造函数,它将以相同的方式隐式添加 - 但它仍然必须有一些东西可以调用。例如,您的场景:

public class A

    public A(int x) 


public class B : A 

导致编译器错误:

错误 CS7036:没有给出与 'A.A(int)' 的所需形参 'x' 对应的参数

但是,您可以显式指定不同的构造函数调用,例如

public B() : base(10)  // Chain to base class constructor

public B() : this(10)  // Chain to same class constructor, assuming one exists

【讨论】:

在 A 类中指定一个显式的空构造函数会消除错误吗? @helloworld:一个无参数的?绝对地。您链接到的构造函数不必由编译器隐式引入 - 它可以是普通的无参数构造函数。或者它甚至可以是一个只有可选参数的,或者只是一个params 参数。基本上,只要: base() 可以工作,就可以了。 这是什么编程语言? @TobiasFeil:C# - 最初在问题标签中,但被另一个用户编辑掉了。【参考方案2】:

class A 提供自己的构造函数后,在class B 对象创建期间不会发生自动调用。

class B 构造函数中的第一行应该是super(paramsToClassAConstructor),或者可以使用this()class B 中调用另一个构造函数。在这种情况下,class B 中的第二个构造函数负责调用 class A 构造函数。

【讨论】:

你写的适用于Java,但问题被标记为C#,它有不同的规则。 天哪..我没有看标签..谢谢你睁大眼睛:)【参考方案3】:

当构造函数完成执行时 - 对象处于有效的初始状态。我们应该使用有效的对象。 当我们为 A 类提供一个非默认构造函数时 - 我们实际上是在说 - 构造 A 类对象,即处于有效的初始状态 - 我们需要更多信息 - 这是由参数提供的。 鉴于此,编译器通过生成默认构造函数来提供帮助。客户端代码将无法编译(因为它应该 - 我们如何让对象处于有效状态?) - 客户端程序员将不得不坐起来注意。 当您提供显式的空构造函数时 - 您实际上是在告诉编译器 - 我知道我在做什么 - 默认构造函数很可能会将字段初始化为一些合理的默认值。 或者促进重用 - 默认构造函数可以调用具有一些默认值的非默认构造函数。 子类知道它的超类 - 子类构造函数可以调用超类方法 - (子类中一些通常重用的方法)。鉴于上述情况 - 这要求超类部分应处于有效状态 - 即其构造函数在其任何方法调用之前执行。这需要在子类构造函数之前调用超级构造函数。 鉴于此 - 您将能够轻松设计构造函数以强制执行正确的初始状态行为

【讨论】:

【参考方案4】:

没有定义基类参数构造函数的特殊规则。规则与其他类构造函数相同。您可以按如下方式定义构造函数的数量:

class baseclass
    
        public baseclass()
        

        
        public baseclass(string message)
        

        
    

如果基类有构造函数,则需要子类或派生类从其基类调用构造函数。

class childclass : baseclass
    
        public childclass()
        
        
        public childclass(string message)
            : base(message)
                    
        
    

【讨论】:

以上是关于C# 继承和默认构造函数的主要内容,如果未能解决你的问题,请参考以下文章

C#面试题整理

继承默认构造函数,矛盾吗?

C# 抽象类有构造函数吗?

[Unity] C#中级编程 - 05 - 构造函数/封装/继承

在 C# 中,您需要调用基本构造函数吗?

在继承的情况下编译器创建默认构造函数和用户创建默认构造函数之间的区别