【问题标题】:If I create a child class from within a parent class, the parent class gets created again如果我从父类中创建子类,则会再次创建父类
【发布时间】:2014-03-05 12:48:58
【问题描述】:

我在试图解决这个问题时迷失了方向,下面是我的代码的一个节略示例。我的问题是,当我从 Bar 对象实例化 Note 对象时,Bar 构造函数被调用 again 然后创建另一个 Note 对象,依此类推,直到出现堆栈溢出错误。

这种递归是否有原因?如何正确创建子类的实例以防止它发生?

编辑:我正在尝试实现一个父类 Bar 的实例与子类的多个实例 Note。这样,每次我创建父类 Bar 时,它都会创建自己的一组注释。这是否必须使用没有任何继承关系的类(只是一个单独的 Bar 和 Note 类)来完成? 我需要在子类中有一个函数(由于其他原因,我不能将此函数移动到父类)调用父类中的一个函数,这将使用 base.RemoveNote(this) 破坏该子类的实例; 有没有更好的方法来做到这一点,或者有没有办法从子类的同一个实例中销毁子类的实例?

代码:

class Bar
{
    private List<Note> notes; 

    public Bar()
    {
        notes = new List<Note>(0);
        notes.Add(new Note())
    }

    public void removeNote(Note note)
    {
        notes.Remove(note);
    }
}

class Note : Bar
{        
    public Note()
    {
        //do stuff
        base.RemoveNote(this);
    }
}

public MainWindow()
{
    private Bar newBar = new Bar();
}

【问题讨论】:

  • 当然会。这就是继承的工作原理……当您有子/父关系时,所有子类都会从父类调用/初始化。默认构造函数被调用。您的代码似乎也不正确。为什么子类会创建父类的实例? (此处为家长注意)。
  • 我到处都看到这是子类的定义 注意(注意:Bar)csharp-station.com/Tutorial/CSharp/lesson08 我应该如何从父类创建子类,我希望子类是注意.谢谢,
  • 你确定Note 扩展栏吗?
  • @user2056201 - 反转您的代码。使 Bar 派生自 Note
  • 看起来 Bar 和 Note 之间的关系应该是“Has”而不是“Is”看看这里的一些答案:stackoverflow.com/questions/2218937/…

标签: c# oop


【解决方案1】:

假设这是在谈论音乐概念,Note 可能不应该继承 Bar。相反,Bar Note 实例。如果两者之间有共同的行为,您可能需要一个共同的基类或接口,如下所示:

public interface IPlayable
{
    void Play();
}

class Bar : IPlayable
{
    private IList<Note> notes = new List<Note> { new Note() }; 

    public void Play() 
    {
        foreach (var note in notes)
        {
            note.Play();
        }
    }
}

class Note : IPlayable
{        
    public Note()
    {
        //do stuff
    }

    public void Play() { /* ... */ }
}

基本上不要将父/子关系与继承关系混淆。仅当两个类具有共同的数据或行为时才使用继承。

【讨论】:

    【解决方案2】:

    您总是可以有条件地在基类中实例化。

    public void Main()
    {
        Bar newBar = new Bar(true);
    }
    
    // Define other methods and classes here
    class Bar
    {
        List<Note> notes; 
    
        public Bar(bool instantiate)
        {
            if(instantiate) {
                notes = new List<Note>(0);
                notes.Add(new Note());
            }
        }
    }
    
    class Note : Bar
    {        
        public Note() : base(false)
        {
            //do stuff
        }
    }
    

    否则,您的代码会出现问题。基类构造函数在派生类构造函数之前调用,因此在您的代码中,每次调用 Note() 构造函数时,都会先调用 Bar() 构造函数,它会调用 Note() 等...

    通过有条件地实例化基类并让派生类使用 Bar(false) 构造函数调用基类,您将在第一次迭代后停止循环。

    对我来说,这似乎是一个奇怪的设计决定。我感觉你不太清楚类派生的目的是什么以及派生类如何继承基类的属性和方法。

    【讨论】:

    • 我很抱歉没有澄清我的问题,我想做的是用 Child 类的多个实例实例化 Parent 类的 1 个实例。这样每次我创建一个 Bar 对象时,我都希望它创建多个 Note 对象。这可能与派生关系有关吗?还是我需要让这两个类完全独立。
    • 派生用于表示从一般到具体的对象层次结构。如果您有一个类 Animal 和一个类 Mammal : Animal,那么 Mammal 在这里被视为一种更具体的 Animal。它有一些与 Animal 相同的功能和属性(吃、睡、身高体重),但它有一些基类没有的(头发)。它还可能覆盖基本功能和属性的实现方式,同时仍为这些事物公开相同的名称。这种关系对您的 Note 和 Bar 有意义吗?一个是另一个更具体的版本吗?
    【解决方案3】:

    这就是我解决问题的方法

    不确定这是否是代表的正确用法,但它对我有用

    delegate void RemoveNoteDelegate(Note note);
    
    class Bar
    {
        private List<Note> notes; 
    
        public Bar()
        {
            notes = new List<Note>(0);
            notes.Add(new Note(removeNote))
        }
    
        public void removeNote(Note note)
        {
            notes.Remove(note);
        }
    }
    
    class Note
    {   
        public RemoveNoteDelegate remove_Note;
    
        public Note(RemoveNoteDelegate remove_Note)
        {
            //do stuff
            remove_Note(this);
        }
    }
    
    public MainWindow()
    {
        private Bar newBar = new Bar();
    }
    

    【讨论】:

    • 您的代表没有做任何事情。从您的代码和构造函数中删除委托,您的 Bar newBar = new Bar() 将具有完全相同的功能。这是因为您的 notes.Remove(note) 方法没有删除注释。我相信这与引用类型和值参数有关。无论如何,目前的代表似乎没有任何目的。
    猜你喜欢
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 2022-01-16
    • 2021-08-11
    • 2013-12-06
    相关资源
    最近更新 更多