从基础 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 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();
}
}
有两种方法可以解决这个问题。先举个例子。
这里我们有包含方法的基础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"
...将发生以下情况:
- 创建了从 B 派生的 A 实例
- A 的 VMT 配置为将对
GetString
的呼叫发送到 A.GetString。
- 你打电话给A.DoSomethingWithGetString
- 这个调用指向 B 的代码库,因为 A 没有实现它。
- B 中的代码库检测到 GetString 是一个虚方法,并使用 VMT 调用它。
- VMT 指向 A 的 GetString 实现。
- 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 的主题。
我是 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 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();
}
}
有两种方法可以解决这个问题。先举个例子。
这里我们有包含方法的基础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"
...将发生以下情况:
- 创建了从 B 派生的 A 实例
- A 的 VMT 配置为将对
GetString
的呼叫发送到 A.GetString。 - 你打电话给A.DoSomethingWithGetString
- 这个调用指向 B 的代码库,因为 A 没有实现它。
- B 中的代码库检测到 GetString 是一个虚方法,并使用 VMT 调用它。
- VMT 指向 A 的 GetString 实现。
- 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 的主题。