当前位置:编程学习 > C#/ASP.NET >>

C#继承问题

class A
{
    public void F()
    {
        Console.WriteLine("A.F");
    }
    public virtual void G()
    {
        Console.WriteLine("A.G");
    }
}

class B : A
{
    new public void F()
    {
        Console.WriteLine("B.F");
    }
    public override void G()
    {
        Console.WriteLine("B.G");
    }
}

class Test
{
    static void Main()
    {
        B b = new B();
        A a = b;
        a.F();
        b.F();
        a.G();
        b.G();
    }
}

 A a = b; 这个a到底是A类的还是B类的啊,为什么 a.F();a.G(); 显示的是B.F B.G呢 谢谢 --------------------编程问答--------------------  A a = b; 这个a到底是A类的还是B类的啊
前面不是用A定义的吗?你觉得呢?他只是用A的子类B来实例化
第二个问题,自己到MSDN去好看看类继承之间的关系 --------------------编程问答--------------------
引用楼主 xie860122 的回复:
A a = b; 这个a到底是A类的还是B类的啊,为什么 a.F();a.G(); 显示的是B.F B.G呢 谢谢


这里只是声明变量a是A类,于是编译器在编译随后的代码时就允许a变量可以引用任何兼容于a类的对象,例如B的子类也是兼容于A类。 --------------------编程问答-------------------- 可以理解为 a 是个披着 A 皮的 B --------------------编程问答-------------------- 可以引用任何兼容于a类的对象  -->  可以引用任何兼容于A类的对象

这是多态的基本概念,也是面向对象与结构化编程的最基本的区别之一。 --------------------编程问答-------------------- a 还是A类,

只是你将 a=b了,

我觉得上面有个人将得很好, a是披着A皮的B类 --------------------编程问答--------------------
引用楼主 xie860122 的回复:
class A
{
    public void F()
    {
        Console.WriteLine("A.F");
    }
    public virtual void G()
    {
        Console.WriteLine("A.G");
    }
}

class B : A
{
    new public void……


楼主,我来给你分析一下代码:

 A a = b; 这个a到底是A类的还是B类的啊? LZ, 里面的 a 是A的 声明 类。 懂? 因为B类是继承A类的,代码很明显, 它首先 B b = new B();这样,B声明了一个b的声明类,而实现类也是B本身(NEW B()), 所以下面代码 A a = b;其实也就是B是实现类,所以打印a.F的时候,调用的B本身,也就是这个方法啦:

 new public void F()
   {
   Console.WriteLine("B.F");
   }

所以打印出来的是方法里的B.F
我们再来分析一下a.G 打印出来的为什么是B.G?
看代码:

 因为小 a 是 A的声明类,所以,而且调用的是a.G这个方法,并没有接实现类,所以这个方法调用自己本身。但。。。。LZ,请仔细看,A类里面的这个方法:

  public virtual void G()
   {
   Console.WriteLine("A.G");
 
很明显它是虚方法。定义了关键字Vritural, 因为B类是继承A类的,我们还要再来看B类的G()方法:

  public override void G()
   {
   Console.WriteLine("B.G");
 
很明显的,对A类的G方法进行了重写,它用了overiride关键字对A类 G 的方法进行重写了。

SO。。。。。打印出来的结果很自然的就是 B.F  和 B.G 了,LZ,懂吗? 不懂,欢迎继续追问。 --------------------编程问答--------------------
引用 6 楼 zhizhuochangeing 的回复:
引用楼主 xie860122 的回复:
class A
{
public void F()
{
Console.WriteLine("A.F");
}
public virtual void G()
{
Console.WriteLine("A.G");
}
}

class B : A
{
new public void……


楼主,我来给你分析一下代码:……

因为对A类的 G 方法 进行了重写,所以调用的就是 B 类的G方法了。打印出来的 结果也 就是B.G了.不知道,这样说 LZ 是否明白? 不明白欢迎 LZ 继续 追问。 --------------------编程问答-------------------- lz根本不理解继承。

继承就是类型的具体化。实际上不是它是B,又可以伪装成A,或者它是A又附加上B。而是,它是A,具体来说,它是B。

这好比,你是人,也是中国人。人和中国人不是两回事,中国人就是人。不存在中国人必须披着人皮才算人,否则还不算中国人了。或者中国人可以剖开身体,从肚子里面掏出一个叫“人”的东西。中国人和人,说的都是同一回事。 --------------------编程问答-------------------- 楼主,你能确认a.F()显示的是B.F? --------------------编程问答-------------------- 看书+单步调试
自己想想,记住就行了。 --------------------编程问答-------------------- B派生于A,一个B的实例化对象b指向了A类的变量a,但是a只能访问b中的基类部分的字段,属性和方法,无法访问派生类的字段,属性和方法,除非是virtual和override标记的.
显然,A.F()将执行A类中的F()
a.F()将显示A.F --------------------编程问答--------------------
引用 6 楼 zhizhuochangeing 的回复:
引用楼主 xie860122 的回复:
class A
{
public void F()
{
Console.WriteLine("A.F");
}
public virtual void G()
{
Console.WriteLine("A.G");
}
}

class B : A
{
new public void……


楼主,我来给你分析一下代码:
……

a.F()这段解释错了. --------------------编程问答-------------------- 内存引用 这一块要好好看下啊 明显a是引用了 b所在的内存的对象啊 --------------------编程问答--------------------
引用 11 楼 schinar 的回复:
B派生于A,一个B的实例化对象b指向了A类的变量a,但是a只能访问b中的基类部分的字段,属性和方法,无法访问派生类的字段,属性和方法,除非是virtual和override标记的.
显然,A.F()将执行A类中的F()
a.F()将显示A.F


我也在纳闷,前面那么多大牛咋都没人发现~
一个个都不看清题目啊~ --------------------编程问答-------------------- 开发还是得细心呀。。 --------------------编程问答-------------------- b.F() and b.G() 没有什么疑问吧,你可能问题是出在 a.F() and a.G()。
a.F() 会找它实际 new 的对象的 F() 方法,但是发现 B 类的 F() 方法被 new 了,所以他往上按照继承线搜索,找到第一个没有被 new 过的继承下来的方法。
a.G() 没什么,G() 被重写,而且 a 变量指向的又是 B 类的对象,所以就调用 B 类的方法 G()。 --------------------编程问答--------------------
引用 16 楼 youzelin 的回复:
a.F() 会找它实际 new 的对象的 F() 方法,但是发现 B 类的 F() 方法被 new 了,所以他往上按照继承线搜索,找到第一个没有被 new 过的继承下来的方法。

A类中的F()方法并不是虚方法(virtual),所以a对象只会执行A类的F()方法,和B类的F()中的new没有关系.即使B类F()定义时没有加New,a.F()也只会执行A类的F()方法.至于B类中F()方法定义时加入new关键字完全是为了消除编译器的警告. --------------------编程问答-------------------- B b = new B();
  A a = b;
主要是这两句话,看第二句,把b方法付给了a  所以后面引用到的都是在a里的 --------------------编程问答-------------------- 这个 A a =b可以解释为:   “a是A,具体的来说a是B”

a是水果,具体来说,他是个苹果。 --------------------编程问答--------------------
引用 2 楼 sp1234 的回复:
引用楼主 xie860122 的回复:
A a = b; 这个a到底是A类的还是B类的啊,为什么 a.F();a.G(); 显示的是B.F B.G呢 谢谢


这里只是声明变量a是A类,于是编译器在编译随后的代码时就允许a变量可以引用任何兼容于a类的对象,例如B的子类也是兼容于A类。

++ --------------------编程问答-------------------- a.F()显示的是应该是A.F吧?测试显示a.F()显示A.F而不是B.F --------------------编程问答--------------------
引用 3 楼 lihanbing 的回复:
可以理解为 a 是个披着 A 皮的 B

经典 --------------------编程问答-------------------- 打印出的结果是:A.F
                B.F
              B.G
              B.G
在多态对象中,调用隐藏方法时,调用的是父类的方法;
          调用覆盖方法时,调用的是子类的方法; --------------------编程问答--------------------
引用 6 楼 zhizhuochangeing 的回复:
引用楼主 xie860122 的回复:
class A
{
public void F()
{
Console.WriteLine("A.F");
}
public virtual void G()
{
Console.WriteLine("A.G");
}
}

class B : A
{
new public void……


楼主,我来给你分析一下代码:……


LZ,不好意思,看错了。我勒个去。。。。

a.F() 这个方法 打印出来的应该是 A.F才对,因为:

A a = b;
a.F();

思路还是没错的,a 是 A 的声明类,b是实现类。 b并没有 实例化 对象。 在来看看 A 类的 F 的方法,子类并没有进行重写。所以。。。调用 的应该是 A 类 自身的 F 方法才对。

所以打印出来的是 A.F 才对。

靠。。。一失足 成千古恨啊。 LZ,不懂的欢迎继续 追问。

最后 打印 出来的 四个 结果是: A.F  B.F  B.G  B.G。 --------------------编程问答--------------------
引用 12 楼 schinar 的回复:
引用 6 楼 zhizhuochangeing 的回复:
引用楼主 xie860122 的回复:
class A
{
public void F()
{
Console.WriteLine("A.F");
}
public virtual void G()
{
Console.WriteLine("A.G");
}
}

class B : A
{
new pub……


哥们,我发现了这个错误,昨天看错了。我勒个去。。。。 --------------------编程问答-------------------- 晕   晕   晕   晕   晕    --------------------编程问答--------------------
引用 22 楼 jiangfling 的回复:
引用 3 楼 lihanbing 的回复:

可以理解为 a 是个披着 A 皮的 B

经典


不知道是苹果披着水果的皮还是水果披着苹果的皮。 --------------------编程问答-------------------- 大家说得好,但没有多少人象楼主这样搞的,这样搞容易误会。

  但在装箱,拆箱却用得到,但不是用父类名,而是用根父类名[object]

你看下面的代码就知到了:
//《1》
  int i = 10;
  object obj = i;//你说obj 不就是10吗。

//《2》
  object  obja =  new A();//obja 又是什么?

//《3》
  object o;
  A a = new A();//[A]
  B b = a;
  o = b;//你说为是什么? 不就是 (//[A])在这里创建得吗。



--------------------编程问答-------------------- 求高手指点下,,  
new public void F()
  {
  Console.WriteLine("B.F");
  }

这个new表示什么?
我是初学者. --------------------编程问答--------------------
引用 29 楼 zwjpos 的回复:
new 
我是初学者.


我知道是的,B 类中 这个new 的这个函数 表示 对基类 A 的同名函数复盖。 --------------------编程问答--------------------
引用 29 楼 zwjpos 的回复:
求高手指点下,,  
new public void F()
  {
  Console.WriteLine("B.F");
  }

这个new表示什么?
我是初学者.


没错,楼上解析的不错。 虽然是New了,但并没有对这个 方法 进行 重写。 --------------------编程问答--------------------
引用 27 楼 sunzongbao2007 的回复:
引用 22 楼 jiangfling 的回复:

引用 3 楼 lihanbing 的回复:

可以理解为 a 是个披着 A 皮的 B

经典


不知道是苹果披着水果的皮还是水果披着苹果的皮。


这个不能说是经典 应该是戴面具而已  
方法的覆盖就是面具把脸盖上了

--------------------编程问答-------------------- 那就是这里面的a 只能访问,基类A中的方法了啊?
还有个问题就是我看了个帖子说的是,
序号  基类(A)中是否有virtual 子类(B)中是否有override 输出(B输出)
1    是                         是             B.G
2    是                              否             B.G
3    否                              是             编译错误
4    否                              否             B.G

请问下这样总结对不对啊 谢谢大家的热心帮助。 --------------------编程问答-------------------- 这个问题不大难吧 --------------------编程问答-------------------- 真没想到这个问题引来了这么多回复。
你可以记住这么多规则,然后去使用,比如多态。
如果你要追根问底,就要去看看CLR是怎么调用实例方法,虚方法(抽像方法本质上也是虚方法),静态方法的。当你理解了这些工作机制,这些问题就迎刃而解了。 --------------------编程问答--------------------
引用 33 楼 xie860122 的回复:
那就是这里面的a 只能访问,基类A中的方法了啊?
还有个问题就是我看了个帖子说的是,
序号  基类(A)中是否有virtual 子类(B)中是否有override 输出(B输出)
1    是                         是             B.G
2    是                              否             B.G
3……


楼主,你首先得理清概念先。看看父类是不是虚方法或者抽象方法(Vritural或Abstract)。 子类有没对父类的方法进行重写(Override),重写了,就对父类的方法就有影响了。 --------------------编程问答-------------------- 我晕,差点改变我一直认为的东西,a.F();明显应该打印A.F --------------------编程问答-------------------- 实践就是真理,

   你用大家的各种说法写出一个对比案例,以后就很难忘记了。 --------------------编程问答--------------------
引用楼主 xie860122 的回复:
class A
{
  public void F()
  {
  Console.WriteLine("A.F");
  }
  public virtual void G()
  {
  Console.WriteLine("A.G");
  }
}

class B : A
{
  new public void F()
  {
  Console.Write……

就像你先买了只狗,然后把它的头和身体包住,然后交给别人告诉别人这是只四条腿的动物。
那它到底是什么呢?撕掉包装它还是只狗,只是可能别人不需要知道而已。 --------------------编程问答--------------------
引用 23 楼 yali_0509 的回复:
打印出的结果是:A.F
                B.F
              B.G
              B.G
在多态对象中,调用隐藏方法时,调用的是父类的方法;
          调用覆盖方法时,调用的是子类的方法;


正解。 --------------------编程问答-------------------- --------------------编程问答-------------------- 看看CLR相关的东西就明白了

A a=b;
a.F();调用的谁,这就看就掌握一个就近原则。
A a只是声明 了一个A类型的指针,其实实体是b.
搞清楚b是个什么类型的东东就OK了嘛。 --------------------编程问答-------------------- 我基类用了Vritural,子类没有用Override,这样到底显示的是继承的基类的值还是子类的值,我在网上看到了不一样的结果,我自己调试是,显示的是子类的, 子类用不用Override都是显示的子类的啊。
基类不用 public void F(),子类也用public void F()  结果显示的也是子类的值, 这样感觉Override 没什么意义了啊,求解 谢谢大家 --------------------编程问答-------------------- 这个是面试中很常见的问题。 --------------------编程问答-------------------- 基础知识的考察吧,不过我们公司一般不会考这些 --------------------编程问答--------------------
引用 23 楼 yali_0509 的回复:
打印出的结果是:A.F
  B.F
  B.G
  B.G
在多态对象中,调用隐藏方法时,调用的是父类的方法;
  调用覆盖方法时,调用的是子类的方法;


正解 --------------------编程问答-------------------- G()是个虚继承函数,F()是被覆盖从写了。a 有指向new B 所以就有了你的结果。 --------------------编程问答-------------------- 这个不太难吧,就是有些混淆 --------------------编程问答--------------------
引用楼主 xie860122 的回复:
class A
{
    public void F()
    {
        Console.WriteLine("A.F");
    }
    public virtual void G()
    {
        Console.WriteLine("A.G");
    }
}

class B : A
{
    new public void……


LZ,你该结贴了。 --------------------编程问答-------------------- 这是多态嘛,同一操作,不同的执行结果,虽然变量是基类,但是在运行时,会执行这个变量的具体类型的方法,如果子类有重写基类的方法,那就执行子类的方法,不然就执行基类的方法了 --------------------编程问答-------------------- 吓死爹了,打开帖子,觉得楼主看错了,override和new一个是虚函数,一个不是,怎么可能会一样?结果,下面一群人一本正经地解释,难道是我的错,害得我启动了一下vs,果然还是楼主看错了,晕。 --------------------编程问答-------------------- 一个是基类  一个是实例化  一个调用  自己想吧 --------------------编程问答-------------------- 面向对象编程主要理解这些名词:类,继承,封装,多态等
这里就是多态。 --------------------编程问答--------------------

class A
{
  public void F()
  {
  Console.WriteLine("A.F");
  }
  public virtual void G()
  {
  Console.WriteLine("A.G");
  }
}

class B : A
{
  new public void F()
  {
  Console.WriteLine("B.F");
  }
  public override void G()
  {
  Console.WriteLine("B.G");
  }
}

class Test
{
  static void Main()
  {
  B b = new B();
  A a = b;
  a.F();
  b.F();
  a.G();
  b.G();
  }
}

昨天刚看了有关C#继承及多态的东西;对于LZ的问题我的理解如下:
首先B b = new B();
    A a = b;
这两行代码:声明了一个A类型对象的引用即a,一个B类型对象的引用即b;
由于A,B之间存在继承关系,这样a,b之间存在赋值兼容性,故可以将一个B类型的变量(b)赋值给A类型的变量的引用。
也即是说:a,b两个应用指向同一个对象(new B()这个对象).注意了这里值相同一个对象是有差别的:对于引用a,只有对象中的基类成分对它是可见的;而对于b,整个对象的所有成分对它都是可见的。这就解释了a.F();的执行结果为"A.F",B累中的F()方法对a不可见。
下一个疑点:为什么a.G()执行的是B类中的G()方法呢?
这就得理解一下virtual、override这两个关键字了:override的作用就是使基类的引用(即a)可以访问派生类中的同名成员(具体而言是相同的签名),而这个成员必须使用override关键字标注,同时基类中的同名成员使用virtual关键字来标注。可以这样理解:执行A.G() 时,本该调用A类中的G()方法,但A类中的G()方法前有virtual关键字,调用即转移到B类中的带override关键字的同名方法,所以最后执行的是B类中的G()方法,结果输出的自然是"B.G".
不知道楼主看懂了我上面说的后,现在有没有搞懂;
其实楼上也有的说到了B类中的F()方法加new关键字只是为了避免编译器的警告,LZ可以去掉那个new,执行结果将是相同的。
说这么多,我觉得LZ最重要的是要理解new,virtual,override这几个关键字的用处 --------------------编程问答-------------------- lz误导人啊。。。我实际测试了下a.F();打印出来的是“A.F”。看上面有些人分析的这么辛苦。。 --------------------编程问答-------------------- 就应该像楼上一下,写代码,调试一下,就知道了啊 --------------------编程问答-------------------- #54楼分析得不错。
--------------------编程问答-------------------- 楼主给的问题都错了。
a.F();a.G() 显示的是A.F B.G,而不是B.F B.G
原因:
1、a.F()是非虚方法,是被b.F() new的,所以调用a.F()的时候不会执行b.F();
2、a.G()是虚方法,是被b.G()override的,所以调用a.G()的时候,会执行b.G().
这就是new和override的区别,也是多态的精髓。 --------------------编程问答-------------------- 楼主给的问题都错了。
a.F();a.G() 显示的是A.F B.G,而不是B.F B.G
原因:
1、a.F()是非虚方法,是被b.F() new的,所以调用a.F()的时候不会执行b.F();
2、a.G()是虚方法,是被b.G()override的,所以调用a.G()的时候,会执行b.G().
这就是new和override的区别,也是多态的精髓。 --------------------编程问答-------------------- 就是就是  楼主写错了吧

public new F(){}这样吧
而且这个执行的应该是A的方法 --------------------编程问答-------------------- 楼主写错了 --------------------编程问答--------------------
引用 3 楼 lihanbing 的回复:
可以理解为 a 是个披着 A 皮的 B



这个问题很经典,3楼答案最准确。 --------------------编程问答-------------------- 1、A和B两个类有继承关系,但两个类中F方法没有任何关系,实现各自不同的逻辑。

2、当调用a.G()方法时,由于该方法是虚方法 ,按照继承链的调用规则,首先调用继承得最远的那个方法也就是B中的G,所以执行Console.WriteLine("B.G");
--------------------编程问答-------------------- 定义一个人类(Person类),该类中包含两个字段name,age。再定义一个学生类(Student类),它是Person类的派生类,该类中包含学号、英语成绩、数学成绩、语文成绩等字段。包含两个方法(方法名自定),一个方法的功能是计算总成绩并输出;另一个方法的功能是根据总成绩判断是否升学,总成绩>=200分时显示可以升学,否则显示不可升学。
在主函数中新建若干个student类的对象(四个以上),分别以学号,姓名,年龄,各科成绩作为参数。并分别调用上述的两个方法。
急求帮助。明天考试要用。
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,