为什么包含对类型B对象的引用的类型A的引用变量不能访问类B的成员函数?

问题描述 投票:2回答:3

为什么objA不能访问methodB(),因为它包含对B类对象的引用?

Class A 
{
     public void methodA()
     {
           .........
     }
}

Class B:A
{
     public void methodB()
     {
          ..........
     }
}

现在

A obj1= new B();

这会抛出一个错误:

obj1.methodB();

为什么? obj1包含对类型B的对象的引用,但仍然无法访问它的成员函数。

c# class object inheritance c#-4.0
3个回答
2
投票

你声明了A类型的变量:

A obj1

并且A没有称为methodB的方法。如果您希望变量的类型为B,请将其声明为:

B obj1= new B();

(这当然意味着你不能将A的任何其他实现存储在该变量中,只有B。)

或者,如果您不想更改变量,则需要转换变量:

(obj1 as B).methodB();

(如果obj1包含A不是B的实现,那么这当然会失败。)

基本上,当您声明类型为A的变量时,编译器会将其保持为A类型。声明后,在变量将包含B实例的任何时候都无法保证。我可以包含任何实现A的实例。


1
投票

当你把这两条线很好地放在一起时,你会想“当然我可以在那个物体上执行methodB()!显然它是一个B!”。

但现在考虑一下:

private void DoSomethingWithAnA(A obj1)
{
    obj1.MethodB();
}

为什么会这样?在这种方法中,你只知道你收到一个对象A,没有人会认为你必须用对象B来调用它。毕竟,如果你的方法想用B做一些事情,它应该要求B,而不是A

当然,我可以使用B调用该方法,这不会是一个问题:

DoSomethingWithAnA(new B());

但这并不意味着DoSomethingWithAnA突然会用B做点什么,它只是用A做点什么。

如果您还想要做一些特定于B的事情,您可以:

private void DoSomething(A obj1)
{
    obj1.MethodA();
    if (obj1 is B)
    {
        ((B)obj1).MethodB();
    }
}

如果你传递B,这个方法会对B做一些事情。但是,它首先需要检查你发送的A是否实际上也是一个B,然后它将A投射到B。在得到的B上,它可以调用MethodB()


0
投票

因为它被称为从基类到派生的限制性视图。如果使用polymorphism实例化对象,就像你执行obj1.methodB();一样,你的obj1只拥有在父类中定义的东西。这是可能的,因为我们知道派生类也必须具有这些定义(字段,属性,方法等)。

这就是为什么你不能调用显式的obj1.methodB();but,你可以用派生类实现调用methodA()

例子:

A objA = new A();
objA.methodA(); //calling method implementation of class A
objA.methodB(); //compile time error  -> class A doesn't have that method

A objA = new B();
objA.methodA(); //calling method implementation of class B
objA.methodB(); //compile time error  -> during restrictive view trough parent class

B objB = new B();
objB.methodA(); //calling method implementation of class B
objB.methodB(); //calling method implementation of class B

想象一下,你有C,D等类,如果用限制性视图实例化它们,你可以为所有这些(子)调用公共方法(在父类中定义)。

List<A> list = new List() {objB,objC,objD};
foreach(A obj in list){
       obj.MethodA();
}
© www.soinside.com 2019 - 2024. All rights reserved.