关于c#在new 一个新对象时的顺序问题

举报
王阿毛 发表于 2019/01/18 10:40:05 2019/01/18
【摘要】 using System;class A{public A(){ PrintFields();}public virtual void PrintFields(){}}class B:A{int x=1;int y;public B(){y=-1;}public override void PrintFields(){Console.WriteLine("x={0},y={1}",x,y...

using System;

class A

{

public A()

{

   PrintFields();

}

public virtual void PrintFields(){}

}

class B:A

{

int x=1;

int y;

public B()

{

y=-1;

}

public override void PrintFields()

{

Console.WriteLine("x={0},y={1}",x,y);

}

问:打印出来的结果应该是什么?


=================================

其实这道题网上的分析及结果一搜一大堆,主要还是想自己捋一捋。

稍后把思路整理一下再编辑


=================================

正确顺序:变量初始化代码,基类构造器,基类构造器中调用虚函数,子类自己的构造器。

基类构造器中调用的虚函数会起作用,因为此时对象已经构建好了,但是只是执行了变量的初始化代码,还没有经过子类自己的构造器的初始化。

==================================

因为构造B之前,先执行变量,y没有明确赋值,默认为0。执行B的构造函数,因为B继承A,所以先执行A的构造函数。A构造函数调用的PrintFields方法在A类里是虚函数,它的实现是在B类,所以执行B类的PrintFields方法,结果输出。虽然继续执行完B的构造函数,使y的值是-1.但结果之前已经输出。 

1-8代表了new B的时候,程序的执行过程。
class A
    {
        public A()//④
        {
            PrintFields();//⑤,发现被重写→⑥
        }
        public virtual void PrintFields() { }
    }
    class B : A
    {
        int x = 1;//①
        int y;//②
        public B()//③,发现继承了A,马上执行A的构造函数
        {
            y = -1;//⑧,到此,创建对象完毕
        }
        public override void PrintFields()//⑥
        {
            Console.WriteLine("x={0},y={1}", x, y);//⑦,输出,此时:x=1,y=0
        }
    }

当程序实例化B时,因为继承关系,,B会先调用其父类的构造方法,,而A的构造中又调用 了 PrintFields 在A中 printFields是虚方法,,所以会调用B中的重写   当调用 PrintFields时 B的构造还未执行,所以y=0而不是-1.所以输出结果是x=1,y=0  如果 B b=new B();b.PrintFields();那么输出结果就是x=1,y=-1

引申一下下边的问题:

public abstract class A

    {

        public A()

        {Console.WriteLine('A');}

        public virtual void Fun()

        {Console.WriteLine("A.Fun()");}

     }

    public class B : A

    {

        public B()

        {Console.WriteLine('B');}

     public new void Fun()

        {Console.WriteLine("B.Fun()");}

     public static void Main()

        {

          A a = new B();

          a.Fun();

            }
}


求问输出结果

 A B A.Fun()


A a=new B();

这里a编译时类型是A,运行类型是B". 所以构造函数的调用就清晰明了吧

然而还是有点奇怪,如果a运行时类型是B的话,那么在调用方法F()时,为什么不调用B的方法F()(而是调用 A 的方法F())呢?

这是因为父类引用指向子类的对象(实例)

这时候 会调用子类重写的方法 但是不能调用父类没有的但是子类有的方法

再有就是override与new得区别

如过程序里面的new换成override输出时是什么样子呢?

将会是 A B B.Fun();这是为什么呢

override的“覆盖”也就是次数重写是指子类覆盖了父类思路方法子类对象无法再访问父类中该思路方法

new是指“隐藏”是指子类隐藏了父类思路方法当然通过定转换可以在子类对象中访问父类思路方法
new 修饰符
使用 new 修饰符显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它

1.B继承A,请问a是A的实例还是B的实例啊?
答:B的实例

2.对象a可以调用A类中的方法吗?可以调用B的方法吗?
答:不一定,如果是虚拟方法,并且在B类重载了A的虚拟方法,a将会调用B的同名方法,普通方法会调用A的方法,

举例:
class A
{
public void MethodA(){...}
public virtual void MethodB(){...}
}

class B:A
{
public new void MethodA(){...}
public override void MethodB(){...}
}

其中,B类重写了A类的普通方法MethodA,也重写了A类的虚拟方法MethodB,则:
A a = new B();
a.MethodA();// 将会调用A类的MethodA方法
a.MethodB();// 将会调用B类的MethodB方


B是A的子类,用A a=new B(),这样定义一个"a", 只能使用B中继承A中的方法或变量,而在B中新增的方法或者变量,"a"不能引用。(也就是 a只能使用B复写A中的方法或

者变量)

专业一点说是:a是A的引用,并创建了B的对象。
简单一点说:a是A的类型,但却拥有了B的功能。

你错在这句话 "而在B中新增的方法或者变量,"a"不能引用"


C#多态性的体现:重载,覆盖,隐藏2009-04-07 14:401.多态的理解

多态性的含义:使得能够利用基类的指针来引用不同子类的对象,以及根据所引用对象的不同,以不同的方式执行相同的操作。

多态的作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

多态分为编译期绑定和运行期绑定。

2.重载,覆盖,隐藏

using System;

using System.Collections.Generic;

using System.Text;


namespace VirtualAPP

{

    class Program

    {

        static void Main(string[] args)

        {

            //一般情况,没有体现多态

            A a = new A();

            a.F();//A.F

            a.G();//A.G

            B b = new B();

            b.F();//B.F

            b.G();//B.G

            b.F(" is overload");

            //体现多态特征

            A a1 = new B();

            a1.F();//A.F,隐藏

            a1.G();//B.G

            Console.ReadLine();

        }

        class A

        {

            public void F()

            { Console.WriteLine("A.F"); }

            public virtual void G()

            { Console.WriteLine("A.G"); }

        }

        class B : A

        {

            //隐藏

            public new void F()

            { Console.WriteLine("B.F"); }


            //重载

            public void F(string str)

            { Console.WriteLine("B.F2"+str); }


            //覆盖

            public override void G()

            { Console.WriteLine("B.G"); }

        }


    }

}
     重载(overload)用于同一类中的成员函数,其特征为:
     * 1)在同一类中
     * 2)相同的函数名
     * 3)参数不同(包括参数类型不同,或参数个数不同,或两者都不同,注意:和返回值没关系)
     * 4)和是否虚函数无关


     覆盖(override)是指派生类函数覆盖基类函数,其特征为:
     * 1)不同的范围(分别位于派生类与基类)
     * 2)相同的函数名称
     * 3)参数相同
     * 4)基类函数必须是虚函数

用法:基类中用virtual修饰符,子类中用override修饰符,重写后,子类对象和基类对象访问该方法时,结果都是在访问子类中重新定义的方法。


    隐藏(hide)是指派生类的函数屏蔽了与其同名的基类函数,其特征为:
     * 1)不同的范围(分别位于派生类与基类)
     * 2)相同的函数名
     * 3)若参数不同,不管基类函数有无virtual关键字,基类函数将会被隐藏。

         若参数相同,基类函数无virtual关键字。基类函数将会被隐藏。
注意:
用法:基类函数virtual修饰符可有可无,子类函数可用new标识隐藏该方法,最后通过基类的引用访问该方法时,访问的仍是基类的函数,子类对象访问的是子类的函数。


【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。