2013-11-05 47 views
1

我在我的c#程序中尝试了下面的代码。这仅仅是为了学习OOP概念。C#创建类和派生类的实例

class a 
    {  
     public void testa() 
     { 
     } 
    } 
    class b:a 
    {  
     public void testb() 
     { 
     } 
    } 

    a a1 = new b(); 

    b b1 = new a(); 

我有关于上述代码的以下查询。

  1. 为什么我在第二行出现错误?
  2. 什么意思是a a1=new b();
  3. 为什么a1.testb()不可访问,即使b的构造函数被分配给a1
  4. a a1=new a()a a1=new b()有什么不同?
+0

可以通过此链接帮助您。 http://msdn.microsoft.com/en-us/library/vstudio/dd460654.aspx –

+0

您需要了解继承的概念。 b类实际上是a类的更加明确和详细的形式。因此,它具有a级所提供的所有功能,但更多。这就是你可以从b引用b的构造函数的原因。现在您需要了解a1.testb()是类b提供的额外功能,哪个类a不具备。所以,a1不能调用testb()。 –

+0

@WasiqAli我会同意你,如果我写了1 =新的a()而不是a1 = new b()。在那种情况下,我不能访问b的方法。但是,既然我将b的构造函数赋值给了为什么它不可访问? –

回答

3

1)如果你的意思是这条线:

b b = new a(); 

这是因为每个ba但不是每一个ab

2-3)什么是a a1=new b(); 为什么a1.testb()意思即使b的构造函数被分配给a1也不可访问?

这意味着你创建b类的对象,但得到引用它作为a(你可以把它低谷此参考不铸件只a甚至是b

+0

你能解释一下,“你可以通过这个参考来对待它,而不是仅仅把它当作b来处理”。 –

+1

对于编译器'a1'只是'a',它可以让你只访问'a'类中定义的fields/properties/methods,但你知道它实际上是'b',你可以写这样的东西(它被称为[cast](http://msdn.microsoft.com/en-us/library/ms173105(v = vs.110).aspx)):'b a2 =(b)a1'和编译器将能够通过'a2'调用'b'的所有方法。 Casting在运行时执行,所以如果'a1'不是'b',它会给你一个运行时错误。 –

+0

[C#大部分是静态类型语言,因为编译器会确定有关每个表达式类型的事实。 C#大多数情况下是一种类型安全的语言,因为它可以防止一种静态类型的值存储在不兼容类型的变量中(以及其他类似的类型错误)。](http://blogs.msdn.com/b/ericlippert /archive/2012/10/15/is-ca-strongly-typed-or-a-weakly-typed-language.aspx) –

1

如果你定义的A1 =新型B (),使用b中声明的方法,你可以为b

a a1 = new b(); 
((b)a1).testb(); 
+0

所以即使分配的构造函数bi将无法访问b的方法使用a1?那么创建一个类的实例是什么意思? –

+0

在运行时将创建变量实例,在编译器将a1视为a的类型之前,除了使用所有方法和其他类型声明的类型为 – DeveloperX

+0

@ user833985之外,还可以有多个从“a”派生的类,但希望将它们存储在一个地方(列表或数组),以便为基类创建存储并将所有内容放在那里。后来如果你想使用派生类的功能,你可以像下面这样引用:'b bInst =(b)aInstance;'。并且您可以获得[基本类的引用的虚拟方法](http://msdn.microsoft.com/zh-cn/library/aa645767(v = vs.71).aspx),但实际上具有一个的派生。 –

0

认为没定义为一个合同,保证某些操作的存在。 类a定义了一个操作,类b继承了a的所有操作并定义了它自己的另一个操作。

第一行:

a a1 = new b(); 

声明了一个名为aa1变量,这意味着你给这个变量应该有任何值的所有操作类型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的实例来满足,因此它只是将值看作是键入a

+0

感谢您提供详细的解释。你能告诉我a1 = new b()的左边部分和右边部分是什么吗?它是否创建了一个b的实例并分配了b()或类似的构造函数? –

+0

@ user833985不,它创建一个'b'的实例并将其赋值给变量'a'。我已经扩展了我对上述问题的描述。 – Rik

2

我将您的类和方法名称更改为现实世界的等价物以更好地理解。我叫aAnimaltestaEat,bHumantestbTalk。所以我们有:

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行为是不可能的。

+0

所以如果即时通讯创建人类b1 = new Animal()的实例;和a1.Talk()不可访问,那么Human b1 = new Animal()之间有什么区别?和动物b1 =新动物(); –

+0

你不能通过实例化一个Animal来创建一个'Human'。请仔细阅读答案。 “动物”不是“人”。斑马,狗,猫,它们是动物,但不是人类。 –

+0

我明白根据你的概念解释,它是不可能的。但理论上我无法说服自己有什么不同b/w人类b1 =新的动物();和动物b1 =新动物(); –

2

可能继承多态性概念对你来说还不是很清楚。 This article可能会帮助你。

如果b类继承自a,则可以将其想象为a的“专业化”。 所以你可以很容易地明白,b可以被用作/看作是一个a的实例,但反过来却不是这样!


为什么即时得到在第2行错误?

因为b b1 = new a();不是有效的赋值。如上所述,您可以将继承的类实例分配给基类变量,但不是相反!

a1 = new b()是什么意思;

此赋值是正确的,因为您肯定可以使用更具体的类实例作为基类实例。

为什么即使b的构造函数被赋值给a1,a1.testb()也不可访问?

当你从一个类继承,这一切阶级的publicprotected方法是继承的,你可以在新类来访问或重写。但testb()不是继承的方法。是b类中定义的新方法,因此只有在完成此作业时才可以使用它:b b1=new b();

+0

但是,在这里我创建了类b的构造函数并将其分配给行a a1 = new b()中的实例a1;那么为什么b的方法不能被a1访问?那么你的意思是说a1 = new a()和a1 = new b()是否相同? –

+0

在类“b”中实现的方法只能在类“b”的实例中调用**。即使你实例化一个新的b(),你也将它分配给一个“a”变量,所以只有类“a”中定义的方法才可用。 – davioooh

+0

so a1 = new a()和a1 = new b()是否相同? –