从基类获取方法?

时间:2017-02-24 21:14:22

标签: c# .net base

我是基类的新手,所以如果我错了或者我应该采取另一种方式,请纠正我,但我在下面编写了一个简单的代码片段,解释了我想要做的事情。

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的方法。

这样做的原因? 我不想填充A类,因为B将会有很多方法,因此将它们保存在B中会更加清晰,然后在其他代码中从A中获取它们。我做错了吗?这不是什么基类吗?我只是希望能够做到这一点:

A.SomeMethodInB();

不使用垃圾填充A类并通过将其存储在B类中来使其更清洁

4 个答案:

答案 0 :(得分:1)

让我总结一下你的问题:

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

这是多态性的最初定义(最近人们更普遍地使用了这个术语)并且在OOP方面是非常好的。对于新人来说,这也是OOP最难掌握的领域。

使用虚方法

编写基类

让我们从基类开始。请注意,我稍微改变了你的例子,我将在稍后解释一下。

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

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

在此示例中,DoSomethingWithGetString调用GetString。请注意GetString是虚拟的。这告诉编译器我们不想在运行时确定GetString的实现位置。这意味着它不能在编译时绑定:相反,它的位置由创建对象时设置的运行时Virtual Method Table标识。如果此代码作为B类实例的一部分运行,那么它将调用B类的GetString实现。 但是如果这个代码是继承的,并且实际上是由来自B类的其他对象调用的,那么它将调用该类的GetString版本。这称为{{3} }。

编写后代类

现在让我们写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已执行。
  8. 因此,您遇到的情况是,B类中的代码正在调用A类中的代码,这就是您要求的内容。

    您也可以这样运行:

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

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

    但我不想在B类

    中进行任何实施

    现在,假设你不希望B类对GetString有任何实现,但你仍然希望能够在A中调用实现。有一种方法可以使用{{3} }。只需添加abstract关键字并删除实现:

    abstract class B
    {
        abstract protected string GetString(); //Notice no implementation
    
        public void DoSomethingWithGetString()
        {
            Console.WriteLine(GetString());
        }
    }
    

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

    无法使用构造函数

    现在,您将在我的示例中注意到我删除了构造函数调用。有一个原因。 构造函数不应该调用在后代类上定义的方法。原因:在构造期间,构造函数在继承层次结构中上下调用,从基类开始向下移动后代链。这意味着,当你调用B的构造函数时,还没有调用A的构造函数。如果A的构造函数尚未运行,我们无法确定A是否已正确设置,因此调用其任何方法都是一个非常糟糕的主意。

    这有一些解决方法,但这是late binding的主题。

答案 1 :(得分:0)

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

如果该方法同时存在Class Bvirtual,则您可以使用override方法和<div class="input-daterange input-group" id="datepicker"> <span class="input-group-addon">from</span> <input type="text" class="input-sm form-control" name="start" /> <span class="input-group-addon">to</span> <input type="text" class="input-sm form-control" name="end" /> </div> $('.input-daterange').datepicker({ autoclose: true, endDate: '+0d' });

答案 2 :(得分:0)

认为在示例中使用名称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();
        }
    }

答案 3 :(得分:0)

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

这里我们有一个包含方法的基类:

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

这是派生类,我们想要调用方法:

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

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

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

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

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

在派生类中,我们现在可以使用关键字override来覆盖基类的虚方法,该方法重新定义它以执行其他操作:

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