从基础 class 获取方法?

Getting methods from base class?

我是 base classes 的新手,所以如果我错了请纠正我,或者我应该用另一种方式来做,但我在下面编写了一个简单的代码片段来解释我想做什么.

class A : B
{
    private int _classId;

    public A (int id) : base(id)
    {
        _classId = id;
    }

    public string GetString()
    {
        return "This will eventually be an important string.";
    }
}

class B
{
    private int _classId;

    public B (int id)
    {
        // here I want to be able to get access to class A's methods
        // such as GetString() ...
    }

    public void SomeMethod()
    {

    }
}

所以我想做的就是让B得到A的方法

这样做的原因? 我不想填充 class A,因为 B 将有很多方法,因此将它们保留在 B 中然后在其他代码中从 A 获取它们会更干净。我做错了吗?这不是 base classes 所做的吗?我只是想仍然能够这样做:

A.SomeMethodInB();

不使用垃圾填充 class A 并通过将其存储在 class B

中使其更清洁

如果方法只在Class A中定义,则无法通过Class B访问它。

如果Class AClass B中都存在该方法,则可以使用virtual方法和override

认为最好在示例中使用名称 BaseClass 和 DerivedClass。名称 A 和 B 有点随意。尽管 A 在 B 之前,但名称并不暗示继承的方向。

class Program
    {
        static void Main(string[] args)
        {
            var bc = new BaseClass(3);
            var dc = new DerivedClass(5);

            Console.WriteLine("Base Class Method A: " + bc.MethodA());
            Console.WriteLine("Derived Class Method A: " + dc.MethodA());
            Console.WriteLine("Base Class Method B: " + bc.MethodB());
            Console.WriteLine("Derived Class Method B: " + dc.MethodB());
            Console.ReadLine();
        }
    }

    public class BaseClass {
        protected int _classId;

        public BaseClass(int classId) {
            _classId = classId;
        }

        public virtual string MethodA() {
            return "Method A in base class: " + _classId.ToString();
        }

        public string MethodB()
        {
            return "I am a method B in the base class: " + _classId.ToString();
        }
    }

    public class DerivedClass : BaseClass {
        public DerivedClass(int classId)
            : base(classId)
        {

        }

        public override string MethodA() {
            return "Method A in derived class: " + _classId.ToString();
        }
    }

有两种方法可以解决这个问题。先举个例子。

这里我们有包含方法的基础class:

public class Base
{
    public void BaseMethod()
    {
        // Some method.
    }
}

这里是派生出来的class,这里我们要调用方法:

public class DerivedClass : BaseClass
{
    // We want to use BaseMethod() here.
}

为了从基础 class 调用方法,我们使用 base 关键字。

public class DerivedClass : BaseClass
{
    base.BaseMethod();
}

如果您只想调用基本方法,这很好。但是,如果我们想改变方法并用不同的函数定义它,我们必须在基础 class 中将其声明为 virtual,如下所示:

public class Base
{
    public virtual void BaseMethod()
    {
        // Some method.
    }
}

在派生的 class 中,我们现在可以使用关键字 override 来覆盖基 class 的虚方法,它重新定义它来做其他事情:

public class DerivedClass : BaseClass
{
    public override void BaseMethod()
    {
        // Some new function.
    }
}

让我总结一下你的问题:

  • 您想要一个仅在后代中实现的方法class (A)
  • 您希望此方法可用于基础 class (B) 和后代 class (A)
  • 您希望基础 class 能够调用后代 class 方法的实现

这是多态性的原始定义(最近人们更普遍地使用该术语)并且是面向对象编程的基础。也是OOP新手最难掌握的地方。

用虚方法写一个基class

让我们从基础开始 class。请注意,我稍微更改了您的示例,稍后我会解释原因。

class B
{
    virtual protected string GetString()
    {
        return "I am a B";
    }

    public void DoSomethingWithGetString()
    {
        Console.WriteLine(GetString());
    }
}

在此示例中,DoSomethingWithGetString 调用 GetString。请注意 GetString 是虚拟的。这告诉编译器我们不想在 运行 之前决定 GetString 的实现在哪里。这意味着它不能在编译时绑定:相反,它的位置由 运行time Virtual Method Table that is set up when the object is created. If this code is running as part of a instance of class B, then it will call class B's implementation of GetString. But if this code was inherited, and is actually being called by some other object that descends from class B, it will call that class' version of GetString. This is called late binding.

标识

写后代class

所以现在让我们写class A:

class A : B
{
    protected override GetString()
    {
        return "I am an A.";
    }
}

因为 A 是 B 的后代,所以我们不需要实现任何其他东西。如果我们调用 A.DoSomethingWithGetString 它实际上会调用 B 的实现,因为它是继承的。

执行

如果你运行这个代码

var a = new A();
a.DoSomethingWithGetString();  //Output = "I am an A"

...将发生以下情况:

  1. 创建了从 B 派生的 A 实例
  2. A 的 VMT 配置为将对 GetString 的呼叫发送到 A.GetString。
  3. 你打电话给A.DoSomethingWithGetString
  4. 这个调用指向 B 的代码库,因为 A 没有实现它。
  5. B 中的代码库检测到 GetString 是一个虚方法,并使用 VMT 调用它。
  6. VMT 指向 A 的 GetString 实现。
  7. A.GetString被执行。

因此,您遇到了 class B 中的代码正在调用 class A 中的代码的情况,这正是您所要求的。

你也可以运行这样:

B b = new A();
b.DoSomethingWithGetString(); //Output = "I am an A"

因此,您有一个指向 B 的指针,表示它是 A,因为它使用的是为 class A 设置的 VMT。

但我不想在 class B

中执行任何操作

现在,假设您不希望 class B 对 GetString 有任何实现,但您仍然希望能够调用 A 中的实现。有一种方法可以做到这一点使用 abstract virtual method。只需添加抽象关键字并删除实现:

abstract class B
{
    abstract protected string GetString(); //Notice no implementation

    public void DoSomethingWithGetString()
    {
        Console.WriteLine(GetString());
    }
}

当然,现在您不能单独使用 class B,因为它需要 GetString 的实现,该实现只会出现在后代 class 中。所以你不能再直接创建 B 的实例;你必须子类型,并使用子类型。

不能使用构造函数

现在,您会注意到在我的示例中我删除了您的构造函数调用。有一个原因。 构造函数不应该调用在后代上定义的方法 class。 原因:在构造过程中,构造函数在继承层次结构中从基类开始向上和向下调用class 并沿着后代链向下移动。也就是说,当你调用 B 的构造函数时,A 的构造函数还没有被调用。如果 A 的构造函数还没有 运行,我们不能确定 A 是否已经正确设置,因此调用它的任何方法都是一个非常糟糕的主意。

有一些解决方法,但这是 different question 的主题。