2012-10-31 20 views
59
class Person 
{ 
    public int age; 
    public Person() 
    { 
     age = 1; 
    } 
} 

class Customer : Person 
{ 
    public Customer() 
    { 
     age += 1; 
    } 
} 

Customer customer = new Customer(); 

お客様の年齢は2歳ですか?基本クラスのコンストラクタが何であっても呼び出されるようです。もしそうなら、最後にbaseに電話する必要があるのはなぜですか?ベースクラスのコンストラクタは自動的に呼び出されますか?

public Customer() : base() 
{ 
    ............. 
} 
+5

技術的には、「age」はプライベートメンバーなので、コンパイルできません。それは働くために '公的なもの 'などである必要があります。 –

+0

申し訳ありませんが、わかりませんでした。しかし、それは私の質問を明確にするためです。 –

+5

静的でないコンストラクタに対して ':base(...)'と ':this(...)のどちらも指定しない場合、デフォルトは':base() 'つまりゼロパラメータの基底クラスのコンストラクタです。 'Person()'コンストラクタが暗黙的に 'Object()'基本クラスコンストラクタを呼び出す最初のクラス 'Person'でもこのことがあります。 ':base()'(ゼロ引数)の記述は常に冗長です。また、 'Person'クラスのコンストラクタが1つ以上のパラメータを取る場合には、再びあなたのサンプルを試してみてください。 –

答えて

51

これは、C#がどのように動作するかを簡単に示したものです。型階層の各型のコンストラクタは、Most Base - > Most Derivedの順に呼び出されます。

したがって、特定のインスタンスでは、Person()を呼び出し、次にコンストラクタオーダーでCustomer()を呼び出します。 baseコンストラクタを使用する必要がある理由は、現在のタイプの下にあるコンストラクタに追加のパラメータが必要な場合です。例:

public class Base 
{ 
    public int SomeNumber { get; set; } 

    public Base(int someNumber) 
    { 
     SomeNumber = someNumber; 
    } 
} 

public class AlwaysThreeDerived : Base 
{ 
    public AlwaysThreeDerived() 
     : base(3) 
    { 
    } 
} 

AlwaysThreeDerivedオブジェクトを構築するために、パラメータなしのコンストラクタがあります。ただし、Baseタイプはありません。したがって、パラメータのないコンストラクタを作成するには、baseの実装で行うことができる基本コンストラクタの引数を指定する必要があります。

+0

あなたの言うことは本当です。しかし、SomeNumberを、例えば乱数に設定したパラメータ化されたコンストラクタに加えて、パラメータのないコンストラクタをBaseが持つのを妨げるものは何もありません。 AlwaysThreeDerivedは引き続きbase(3)呼び出しを使用しますが、別のクラス(RandomDerivedと呼ぶ)は、そのパラメータのないBaseコンストラクタを指定せずにbaseから派生することができます。 –

+0

修正 - 私は、基本コンストラクタを明示的に呼び出すために最も頻繁に使用される理由の簡単な例を挙げています。 – Tejs

+0

合意(+1)。自己宣言された初心者からそれを隠そうとしませんでした。 :) –

37

はい、基本クラスのコンストラクタが自動的に呼び出されます。引数のないコンストラクタがある場合は、base()への明示的な呼び出しを追加する必要はありません。

施工後にお客様の年齢を印刷することで簡単にテストできます(link to ideone with a demo)。

9

デフォルトのパラメータなしのコンストラクタを持っていなかった場合は、パラメータで1を呼び出す必要があるでしょう:

class Person 
{ 
    public Person(string random) 
    { 

    } 
} 

class Customer : Person 
{ 
    public Customer(string random) : base (random) 
    { 

    } 
} 
+1

うん、それは私が探していたものだ、ありがとう。 – DrNachtschatten

0

私は追加することがあまりありませんが、私は私がする必要があることを発見しましたMyConstructor()を呼び出す:base()(1つのケースにパラメータがない)私はRegisterProperties()仮想関数を持つ方法でINotifyPropertyChangedを実装する基本クラスを持っています。それをオーバーライドすると、ベースコンストラクタで呼び出されます。したがって、オーバーライドされた仮想が認識される前に基底が明らかに呼び出されたので、最後に派生したサブクラスで呼び出す必要があります。私の物件は私がこれをしなければ通知しません。基本クラス全体が下にあります。

データベースの直下にDatabaseTraitsサブクラスを追加しました。空のbase()呼び出しがなければ、私のプロパティはOnPropertyChanged()を呼び出さない。 C#で

[DataContract] 
public abstract class DataModelBase : INotifyPropertyChanged, IDataErrorInfo { 

    #region Properties 

    [IgnoreDataMember] 
    public object Self { 
     get { return this; } 
     //only here to trigger change 
     set { OnPropertyChanged("Self"); } 
    } 

    #endregion Properties 

    #region Members 

    [IgnoreDataMember] 
    public Dispatcher Dispatcher { get; set; } 

    [DataMember] 
    private Dictionary<object, string> _properties = new Dictionary<object, string>(); 

    #endregion Members 

    #region Initialization 

    public DataModelBase() { 
     if(Application.Current != null) Dispatcher = Application.Current.Dispatcher; 
     _properties.Clear(); 
     RegisterProperties(); 
    } 

    #endregion Initialization 

    #region Abstract Methods 

    /// <summary> 
    /// This method must be defined 
    /// </summar 
    protected abstract void RegisterProperties(); 

    #endregion Abstract Methods 

    #region Behavior 

    protected virtual void OnPropertyChanged(string propertyName) { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    protected bool RegisterProperty<T>(ref T property, string propertyName) { 
     //causes problems in design mode 
     //if (property == null) throw new Exception("DataModelBase.RegisterProperty<T> : ref T property cannot be null."); 
     if (_properties.ContainsKey(property)) return false; 

     _properties.Add(property, propertyName); 

     return true; 
    } 

    protected string GetPropertyName<T>(ref T property) { 
     if (_properties.ContainsKey(property)) 
      return _properties[property]; 

     return string.Empty; 
    } 

    protected bool SetProperty<T>(ref T property, T value) { 
     //if (EqualityComparer<T>.Default.Equals(property, value)) return false; 
     property = value; 
     OnPropertyChanged(GetPropertyName(ref property)); 
     OnPropertyChanged("Self"); 

     return true; 
    } 

    [OnDeserialized] 
    public void AfterSerialization(StreamingContext context) { 
     if (Application.Current != null) Dispatcher = Application.Current.Dispatcher; 
     //---for some reason this member is not allocated after serialization 
     if (_properties == null) _properties = new Dictionary<object, string>(); 
     _properties.Clear(); 
     RegisterProperties(); 
    } 

    #endregion Behavior 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion INotifyPropertyChanged Members 

    #region IDataErrorInfo Members 

    string IDataErrorInfo.Error { 
     get { throw new NotImplementedException(); } 
    } 

    string IDataErrorInfo.this[string propertyName] { 
     get { throw new NotImplementedException(); } 
    } 

    #endregion IDataErrorInfo Members 

} //End class DataModelBaseclass DataModelBase 

/*I decided to add an example subclass*/ 
    [DataContract] 
public abstract class DatabaseTraits : DataModelBase { 
    #region Properties 
    private long _id = -1; 
    [DataMember] 
    public long Id { 
     get { return _id; } 
     set { SetProperty(ref _id, value); } 
    } 
    private bool _isLocked = false; 
    [DataMember] 
    public bool IsLocked { 
     get { return _isLocked; } 
     set { SetProperty(ref _isLocked, value); } 
    } 

    private string _lockedBy = string.Empty; 
    [DataMember] 
    public string LockedBy { 
     get { return _lockedBy; } 
     set { SetProperty(ref _lockedBy, value); } 
    } 

    private DateTime _lockDate = new DateTime(0); 
    [DataMember] 
    public DateTime LockDate { 
     get { return _lockDate; } 
     set { SetProperty(ref _lockDate, value); } 
    } 

    private bool _isDeleted = false; 
    [DataMember] 
    public bool IsDeleted { 
     get { return _isDeleted; } 
     set { SetProperty(ref _isDeleted, value); } 
    } 
    #endregion Properties 

    #region Initialization 
    public DatabaseTraits() : base() { 
     /*makes sure my overriden RegisterProperties() is called.*/ 
    } 
    protected override void RegisterProperties() { 
     RegisterProperty(ref _id, "Id"); 
     RegisterProperty(ref _isLocked, "IsLocked"); 
     RegisterProperty(ref _lockedBy, "LockedBy"); 
     RegisterProperty(ref _lockDate, "LockDate"); 
     RegisterProperty(ref _isDeleted, "IsDeleted"); 
    } 
    #endregion Initialization 

    #region Methods 
    public void Copy(DatabaseTraits that) { 
     Id = that.Id; 
     IsLocked = that.IsLocked; 
     LockedBy = that.LockedBy; 
     LockDate = that.LockDate; 
     IsDeleted = that.IsDeleted; 
    } 
    #endregion Methods 
} 
0

はベースを使用して派生クラスは、派生クラスから基底クラスの一部のコンストラクタにSOME暗黙的または明示的なCALLがなければなりません。

私はその事実を理解するまで、これがどのように働いたのか分かりませんでした。

つまり、ベースクラスを派生クラスに接続する場合、派生クラスから基本クラスでいくつかのコンストラクタを呼び出す必要があります。基本クラスは、基本クラスのコンストラクタを呼び出すことによって、派生クラスから常に最初にインスタンス化されます。 C#は、デフォルトのコンストラクタか、パラメータを持つデフォルト以外のコンストラクタかどうかは気にしません。そのため、基本クラスにパラメータを持つ非コンストラクタが他にない場合にのみ、暗黙的に呼び出されるため、すべてのクラスにデフォルトコンストラクタを残すことができます。

パラメータでデフォルト以外のコンストラクタを突然追加すると、デフォルトの非表示のデフォルトコンストラクタチェーンの作成と呼び出しが中断されます。デフォルトではないコンストラクタを持つBaseクラスでは、派生クラスからそのコンストラクタを明示的に呼び出すか、ベースクラスに明示的にデフォルトのコンストラクタを追加する必要があります。

仕事上のすべての項目の理由がどちらかである

// THIS WORKS!!! 
class MyBaseClass0 
{ 
    // no default constructor - created automatically for you 
} 
class DerivedClass0 : MyBaseClass0 
{ 
    // no default constructor - created automatically for you and calls the base class default constructor above 
} 

// THIS WORKS!!! 
class MyBaseClass1 
{ 
    // same as above 
} 
class DerivedClass1 : MyBaseClass1 
{ 
    public DerivedClass1() 
    { 
     // here the derived class default constructor is created explicitly but the call to the base class default constructor is implicitly called 
    } 
} 

// AND THIS WORKS!!! 
class MyBaseClass2 
{ 
    // as above 
} 
class DerivedClass2 : MyBaseClass2 
{ 
    public DerivedClass2() : base() 
    { 
     // here we explicitly call the default constructor in the base class using base(). note its optional as base constructor would be called anyway here 
    } 
} 

// AND THIS WORKS!!! 
class MyBaseClass3 
{ 
    // no default constructor 
} 
class DerivedClass3 : MyBaseClass3 
{ 
    public DerivedClass3(int x)//non-default constructor 
    { 
     // as above, the default constructor in the base class is called behind the scenes implicitly here 
    } 
} 

// AND THIS WORKS 
class MyBaseClass4 
{ 
    // non default constructor but missing default constructor 
    public MyBaseClass4(string y) 
    { 

    } 
} 
class DerivedClass4 : MyBaseClass4 
{ 
    // non default constructor but missing default constructor 
    public DerivedClass4(int x) : base("hello") 
    { 
     // note that here, we have fulfilled the requirement that some constructor be called in base even if its not default 
    } 
} 

// BUT THIS FAILS!!!...until you either add in a base() call to the non-default constructor or add in the default constructor into base! 
class MyBaseClass5 
{ 
    // 1. EITHER ADD MISSING DEFAULT CONSTRUCTOR HERE AND CALL IT USING base() below.... 
    public MyBaseClass5() { } 

    // 2. Or use the non-default constructor and call to base("hello") below 
    //public MyBaseClass5(string y) 
    //{ 
    //} 
} 
class DerivedClass5 : MyBaseClass5 
{ 
    public DerivedClass5(int x) : base()// 1. Either ADD explicit call here to explicit default constructor in base class 
    { 
    } 

    //public DerivedClass5(int x) : base("hello")// 2. Or ADD explicit call here to parameter-based constructor in base class 
    //{ 
    //} 
} 

.....さんはこれをテストしてみましょう:基底クラスのデフォルトコンストラクタへ 1.コールは、暗黙的に基底クラスで作成され、何の非デフォルトコンストラクタは、基本クラスまたは 2に追加されていないため、暗黙的に混乱していますどのようなベース(myparamter)

  • を使用して、デフォルト以外の、パラメータベースのコンストラクタを明示的に呼び出しがあります派生からと呼ばれますいつ、なぜ、def aultコンストラクタは基本クラスで作成され、派生クラスから呼び出されます。これは、デフォルト以外のコンストラクタがベースにない場合にのみ発生します。
関連する問題