繁体   English   中英

如何告诉继承类不调用其基类'无参数构造函数?

[英]How can I tell the inheriting class to not call its base class' parameter-less constructor?

我很惊讶地发现,无论何时调用派生类中的任何构造函数,都会调用我的基类的无参数构造函数。 我认为这就是: base()用于显式调用基本构造函数,如果我想要的话。

在实例化派生类时,如何防止调用基本构造函数?

using System;

namespace TestConstru22323
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer("Jim", "Smith");
            Customer c = new Customer();
            Console.WriteLine(customer.Display());

            Console.ReadLine();
        }
    }

    public class Person
    {
        public Person()
        {
            Console.WriteLine("I don't always want this constructor to be called. I want to call it explicitly.");
        }
    }

    public class Customer : Person
    {
        private string _firstName;
        private string _lastName;

        //public Customer(string firstName, string lastName): base()  //this explicitly calls base empty constructor
        public Customer(string firstName, string lastName) //but this calls it anyway, why?
        {
            _firstName = firstName;
            _lastName = lastName;
        }

        public string Display()
        {
            return String.Format("{0}, {1}", _lastName, _firstName);
        }
    }
}

唯一的方法是明确告诉它你想要它调用哪个其他基地; 这当然意味着你必须选择一些基本的ctor来打电话。

根本不能称之为基础ctor - 概念上 ,构建Customer是通过首先构建一个Person ,然后在它之上进行Customer特定的构建来完成的。 例如,假设Personprivate字段 - 如果允许构建Customer 首先构造Person那么这些字段将如何正确构造?

在.NET中,无论您是否调用:base() ,都将调用对象层次结构中的每个对象构造函数。

:base()如果没有显式调用它,则会隐式调用:base()

如果要在父对象上调用不同的构造函数而不是默认构造函数,则可以使用:base()

如果你的父构造函数中的代码每次都不应该调用,那么将代码移动到它自己的方法可能会更好,这种方法需要在构造对象后显式调用。 或者,在父对象上创建一个参数化构造函数,并使用该参数来确定是否应该执行代码。

例如:

:base(true) - This executes your code.
:base(false) - This does not execute your code.

正如其他人所指出的,派生实例必须调用其基类之一的构造函数。

如果要控制基类的初始化逻辑的执行,请删除其默认构造函数并将其替换为如下所示:

public class Base {
    // Base has no default constructor
    public Base(bool initialize) {
        if (initialize) {
            // ... logic here 
        }
    }    
}

派生的构造函数看起来像这样:

// Derived1 executes the initialization logic
public Derived1(): base(true) {}

// Derived2 does not
public Derived2(): base(false) {}

一种方法是使您的基本默认构造函数成为私有,但只有在基类中创建一个帮助器构造函数时才会有效,只有在您明确需要它时才调用私有构造函数。

class Base
{
  private Base() { ... special default base logic ... }
  protected Base(... params ...) : this() { ... exposed base that calls private cons ... }
  protected Base(... other params ...) /* no default call */ { ... exposed cons that doesnt call default ...}
}

class DerivedNoCall
{
  public DerivedNoCall() : base(... other params ...) {} //<-- will NOT call default base
}

class DerivedDoCall
{
  public DerivedDoCall() : base(... params ...) {} //<-- WILL call default base cons indirectly
}

这是非常人为的, @ aakashm有最好的答案。

您只需要为某些派生对象调用构造函数的要求不符合面向对象的原则。 如果它是一个人,那么它需要这样构建。

如果需要对某些对象进行共享初始化,则应考虑创建Initialize方法或添加将由特定派生对象调用的参数化构造函数。

参数化的构造函数方法感觉有点尴尬:

public abstract class Person
{
    protected Person()
    {
    }

    protected Person( bool initialize )
    {
        if (initialize)
        {
            Initialize();
        }
    }

    // ...
}

public class Customer : Person
{
    public Customer(string firstName, string lastName)
    {
       // ...
    }
}

public class Employee : Person
{
    public Customer(string firstName, string lastName) : base(true)
    {
       // ...
    }
}

您可以使默认基本构造函数protected ,然后只为基础及其子项创建非默认构造函数。

编辑

您可以为基类提供具有不同签名的protected构造函数(例如受保护的枚举类型),并将初始化代码放在那里,而默认构造函数也protected ,不会进行特定的初始化。

实例化类时,继承层次结构中的所有类都从最顶层的Parent到最下面的子节点进行实例化,停止在您实例化的类型上。 因此,如果您实例化System.Text.StringBuilder(),首先调用System.Object的默认构造函数,然后调用StringBuilder()。 您可以使用base关键字来调用不同的构造函数(一个具有相同或更少的参数),但不能使用更多的参数。 如果未指定base,则会调用默认构造函数,因此会发生这种情况。 您还可以在实例方法的上下文中使用base关键字来调用基本实现,例如在装饰器模式的情况下。 如果您不想调用基类私有构造函数,那么您应该使用私有默认构造函数设置子项,并在其他构造函数上显式调用base(params)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class ProcessCaller
    {
        static void Main()
        {
            MyDerived md1 = new MyDerived(1);
            object o = new System.Text.StringBuilder();//This will implicitly instantiate the classes in the inheritance hierarchy:  object, then stringbuilder
        }
    }

public class MyBase
{
   int num;

   public MyBase() 
   {
      Console.WriteLine("in MyBase()");
   }

   public MyBase(int i )
   {
      num = i;
      Console.WriteLine("in MyBase(int i)");
   }

   public virtual int GetNum()
   {
      return num;
   }
}

public class MyDerived: MyBase
{
   //set private constructor.  base(i) here makes no sense cause you have no params
   private MyDerived()
   {

   }

    // Without specifying base(i), this constructor would call MyBase.MyBase()
   public MyDerived(int i) : base(i)
   {
   }
   public override int GetNum()
   {
       return base.GetNum();//here we use base within an instance method to call the base class implementation.  
   }
}

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM