[英]Getting methods from base class?
我是基础类的新手,所以如果我错了或者应该以另一种方式进行操作,请更正我,但是我在下面编写了一个简单的代码段,以解释我想要做什么。
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类中使其变得更清洁
让我总结一下您的问题:
这是多态性的最初定义(最近人们一直在更广泛地使用该术语),并且在涉及OOP时是头疼的。 对于新来者来说,这也是OOP最难掌握的领域。
让我们从基类开始。 请注意,由于您稍后将要解释的原因,我对您的示例进行了一些更改。
class B
{
virtual protected string GetString()
{
return "I am a B";
}
public void DoSomethingWithGetString()
{
Console.WriteLine(GetString());
}
}
在此示例中, DoSomethingWithGetString
调用GetString
。 请注意, GetString
是虚拟的。 这告诉编译器,我们不想在运行时决定GetString
的实现在哪里。 这意味着它不能在编译时绑定:相反,它的位置由创建对象时建立的运行时虚拟方法表标识。 如果此代码作为类B的实例的一部分运行,则它将调用类B的GetString
实现。 但是,如果此代码是继承的,并且实际上是由类B派生的其他某个对象调用的,则它将调用该类的GetString
版本。 这称为后期绑定 。
现在让我们来编写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"
...将发生以下情况:
GetString
调用发送到A.GetString。 因此,您遇到一种情况,即B类中的代码正在调用A类中的代码,这正是您所要求的。
您也可以这样运行它:
B b = new A();
b.DoSomethingWithGetString(); //Output = "I am an A"
因此,您有一个指向B的指针,说它是A,因为它使用的是为类A设置的VMT。
现在,假设您不希望B类对GetString完全具有任何实现,但是您仍然希望能够在A中调用该实现。有一种方法可以使用抽象的虚方法来实现 。 只需添加abstract关键字并删除实现:
abstract class B
{
abstract protected string GetString(); //Notice no implementation
public void DoSomethingWithGetString()
{
Console.WriteLine(GetString());
}
}
当然,现在您不能单独使用类B,因为它需要仅在后代类中存在的GetString实现。 因此,您不再可以直接创建B的实例。 您必须先进行子类型化,然后再使用子类型。
现在,您会在示例中注意到我删除了构造函数调用。 有一个原因。 构造函数永远不要调用在后代类上定义的方法。 原因:在构造过程中,构造函数在继承层次结构中上下移动,从基类开始,在子孙链中向下移动。 这意味着,当您调用B的构造函数时,尚未调用A的构造函数。 如果A的构造函数尚未运行,则无法确定A的设置是否正确,因此调用其任何方法是一个非常糟糕的主意。
有一些解决方法,但这是另一个问题的主题。
如果该方法仅在Class A
定义,则无法通过Class B
访问它。
如果该方法同时存在于Class A
和Class 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();
}
}
有两种方法可以解决此问题。 首先让我举一个例子。
这里我们有一个包含方法的基类:
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.
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.