我是基类的新手,所以如果我错了或者我应该采取另一种方式,请纠正我,但我在下面编写了一个简单的代码片段,解释了我想要做的事情。
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类中来使其更清洁
答案 0 :(得分:1)
让我总结一下你的问题:
这是多态性的最初定义(最近人们更普遍地使用了这个术语)并且在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"
......将发生以下情况:
GetString
的调用发送到A.GetString。因此,您遇到的情况是,B类中的代码正在调用A类中的代码,这就是您要求的内容。
您也可以这样运行:
B b = new A();
b.DoSomethingWithGetString(); //Output = "I am an A"
因此,您有一个指向B的指针,表示它是A,因为它正在使用为A类设置的VMT。
现在,假设你不希望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 B
和virtual
,则您可以使用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.
}
}