【问题标题】:How do you call a method of a class in a certain level of the hierarchy, not the lowest one?您如何在层次结构的某个级别而不是最低级别中调用类的方法?
【发布时间】:2013-12-01 04:37:21
【问题描述】:

说我有:

class Foo
{
    string name1;
    public Foo(string name1)
    {
        this.name1 = name1;
        something();
    }
    virtual void something()
    {
       Console.WriteLine("Hello, " + name1);
    }
}

class Bar inherits Foo
{
    public Bar(string name1, string name2) : base(name1)
    {
        this.name2 = name2;
        something();
    } 

    override void something()
    {
        Console.WriteLine("Good bye, " + name2);
    }
}

我想要完成的是Foo 构造函数上的something() 调用Foo 定义的something,而不是Bar 定义的那个。 但如果我这样做:

Bar b = new Bar("A", "B");

Bar 构造函数调用 Foo 构造函数,该构造函数调用由 Bar 而非 Foo 定义的 something

我知道我想做的是一个糟糕的面向对象设计。我这样做是为了优化。

有可能吗?谢谢。

【问题讨论】:

  • 你可以尝试重载而不是覆盖
  • 您缺少 virtual 关键字。
  • 这会导致糟糕的 OOP 设计。如果您打算在基础对象上调用某些东西 - 让它显而易见。您不想在基类和子类之间混合实现。正如另一个发布的那样 - base.Something() 是确保从正确位置调用它的最佳方法。
  • “我这样做是为了优化。”什么样的优化?你能给我们解释一下吗?也许有更好的解决方案。
  • @svick,当然。我正在为我正在学习的课程做一个编译器。通过“优化”,我指的是对解析树进行尽可能少的传递。 “某事”实际上代表我在解析的同时尝试执行的传递,因此,我在构造的构造函数中调用了某些东西。我相信一个好的 OOP 设计会建议不要在初始化时调用不需要初始化的方法。

标签: c# inheritance methods hierarchy


【解决方案1】:

为什么不使用Bar 类中的base.something()

public class Foo
    {
        string name1;
        public Foo(string name1)
        {
            this.name1 = name1;
        }

        public virtual void something()
        {
            Console.WriteLine("Hello, " + name1);
        }
    }

    public class Bar : Foo
    {
        private string name2;

        public Bar(string name1, string name2)
            : base(name1)
        {
            this.name2 = name2;
            something();
        }

        public override void something()
        {
            base.something();
            Console.WriteLine("Good bye, " + name2);
        }
    }

输出为 name1= A 和 name2= B 将是: “你好,A” “再见,B”

【讨论】:

  • 但是如果我创建一个 Foo,就不会调用某些东西。
  • 然后将 Foo 编写为抽象类,并为您的实现使用两个派生类。这样您就可以消除对基类的这种逻辑依赖。
【解决方案2】:

new关键字在Bar中声明something方法:

new void something()
{
    Console.WriteLine("Good bye, " + name2);
}

这样,Foo 类中的每个something 调用都将调用Foo.something。而且您无法从那里拨打Bar.something

这样,您可以调用Foo.something,只需将您的Bar 对象转换为Foo

((Foo)barInstance).something() // calls Foo.something()
barInstance.something() // calls Bar.something()

另一种保持多态性的方法:从Foo 构造函数中调用不同的方法。

class Foo
{
    string name1;
    public Foo(string name1)
    {
        this.name1 = name1;
        somethingImpl();
    }
    virtual void something()
    {
       somethingImpl();
    }
    private void somethingImpl()
    {
       Console.WriteLine("Hello, " + name1);
    }
}

【讨论】:

  • 但这(您的第一个选择)违背了拥有Foo.something virtual 的目的。另外,我认为为Bar.something 使用不同的名称会比new 更清晰。
  • @svick 是的,我同意。我已将其添加为解决问题的另一种方法。
  • 关于第二个选项,我不会有同样的问题吗? Bar 会调用 Foo,而后者会调用 Bar 的 somethingImpl()?没关系,这就是将其设为私有的目的……我明白了。
  • Bar 构造函数将调用Foo 构造函数(由:base()),后者将调用somethingImpl
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多