我在c#程序中尝试了以下代码。这只是为了学习OOPs概念。
class a
{
public void testa()
{
}
}
class b:a
{
public void testb()
{
}
}
a a1 = new b();
b b1 = new a();
我对上述代码有以下疑问。
a a1=new b()
; a1.testb()
的构造函数已分配给b
,为什么a1
无法访问?a a1=new a()
和a a1=new b()
之间的区别是什么?答案 0 :(得分:3)
1)如果你的意思是这一行:
b b = new a();
这是因为每个b
都是a
,但不是每个a
都是b
2-3)a a1=new b();
的含义是什么
即使a1.testb()
的构造函数已分配给b
,为什么a1
无法访问?
这意味着您创建了b
类的对象,但是将其引用为a
(您可以通过此引用将其视为a
,即使它是b
}})
答案 1 :(得分:2)
我将您的类和方法名称更改为真实世界,以便更好地理解。我将a
命名为Animal
,将testa
命名为Eat
,将b
命名为Human
,将testb
命名为Talk
。所以我们有:
class Animal {
public void Eat() { }
}
class Human : Animal {
public void Talk() { }
}
Animal a1 = new Human();
Human b1 = new Animal();
好的,回到你的问题。
1)你在第二行得到错误,因为每只动物都不是人类。是吗?
2)a1=new b()
根据我们新的命名惯例,转为a1 = new Human
,这意味着Animal a1 = new Human
。所以,这是正确的,因为人类是一种动物。
3)a1.testb()
根据我们新的命名惯例,转为a1.Talk()
。好吧,a1
是动物(Animal a1
),我们不能指望动物说话。
更多强>
认为class
是一组属性和行为。例如,我们有一个名为Animal
的组,用于定义Eat
行为。另一个名为Human
的组扩展了Animal
组,并且它有自己的行为,名为Talk
。众所周知,Human
也有其超群体行为 - 例如。在此示例中为Eat
- 。
当我们有一个小组Animal
的实例时,我们可以期待它吃。但我们不能要求它说话。这是不可能的。另一方面,我们从组Human
中选择的每个项目实际上都是Animal
。所以我们可以请他吃饭。
如果我们有Human
个实例,我们可以让他表现为Human
和Animal
。我的意思是,我们可以问他Talk
,我们也可以问他Eat
。每个Human
可以位于人类组和动物组中。
1)当我们说Human b1 = new Animal();
时,它确切地说:从Animal
组中获取项目 - 右侧部分 - 并将其放入Human
组 - 左侧部分 - 这是不可能的。因为有很多动物不是人类。
2)当我们说Animal a1 = new Human
时:从Human
组中获取一个项目 - 右侧部分 - 并将其放入Animal
组 - 左侧部分 - 这很容易实现。
3)当我们说a1.Talk()
时,我们希望Animal
能够说话。我的意思是我们希望Animal
行为Human
行为是不可能的。
答案 2 :(得分:2)
可能继承和多态概念对您来说还不是很清楚。 This article可能会对您有所帮助。
如果班级b
继承自a
,您可以将其视为a
的“专业化”。
因此,您可以很容易地理解b
可以被用作/看作a
实例,但反之则不然!
为什么我在第二行遇到错误?
因为b b1 = new a();
不是有效的作业。如上所述,您可以将继承的类实例分配给基类变量,但不能相反!
a1 = new b();
是什么意思
这个赋值是正确的,因为你肯定可以使用更具体的类实例作为基类实例。
为什么a1.testb()无法访问,即使将b的构造函数分配给a1?
当您从类继承时,此类的所有public
和protected
方法都将被继承,您可以在新类中访问或覆盖它。但testb()
不是继承的方法。是在类b
中定义的新方法,因此只有在执行此分配时才能使用它:b b1=new b();
答案 3 :(得分:1)
如果你定义了a1 = new b(),要使用b中声明的方法,你可以将a1转换为b
a a1 = new b();
((b)a1).testb();
答案 4 :(得分:1)
将您的课程视为合同,保证某些操作的存在。
类a
定义了一个操作,类b
继承了a
的所有操作,并定义了另一个操作。
第一行:
a a1 = new b();
声明一个名为a1
的{{1}}类型的变量,这意味着你赋予的任何值,这个变量应该具有a
所需的所有操作。 a
创建了一个新的类new b()
实例,该实例已分配给变量b
。由于类a1
继承了类型b
中的所有操作,因此可以将类型a
的值分配给类型为b
的变量。
在第二行:
a
类似地,您定义一个变量,该变量应具有由b b = new a();
类型定义的所有操作。但是,由于您输入了b
类型的值,该值未定义a
操作类型testb
所需,因此编译器不接受此操作。
关于第三个问题,编译器只知道变量的类型(b
),而不知道实际分配给它的值。你基本上告诉编译器“我保证这个值将定义a
操作。现在让它进行操作testa
!”编译器不知道变量的实际值,因此就其而言,这是不可能的。
至于testb
和a a1=new a()
之间的差异:
在这两种情况下,都会创建一个a a1=new b()
类型的变量。在第一个表达式中,分配给此变量的值是新创建的类型a
的实例,而在第二个表达式中,该值是新创建的类型a
的实例。由于类型“b”基本上是类型b
的扩展版本,因此编译器知道类型a
的实例也可以满足您对a
类型实例的所有要求。 ,所以它只是将值视为b
类型。
答案 5 :(得分:0)
1)每个b
都是a
,但相反的情况并非如此。
2)是多态性Polymorphism - Define In Just Two Sentences
的一个例子 3)a1.testb()
无法访问,因为您将其视为a
的实例,其中没有testb()
的定义