【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
公司项目是窗体应用程序,c#开发的。在看代码了过程中遇到了一个疑问,引发了如下思考。
=============问题==================
疑问:要显示的窗体是frmmain是继承自customFrm这样的基窗体的。当我实例化frmmain窗体的时候,(new frmmain()) as customFrm).show().我发现子窗体和父窗体的内容都能全部显示出来。当然我们需要的就是这样。但是问题就来了。既然实例化子类,然后强制转化为父类。那么父类就只能调用父类本身的成员,而无法做到访问子类成员了,那么子类的成员是这么在界面上显示出来的? 写了个简单的demo,具体化这个问题
一个父类B如下:
public class B
{
public B()
{
}
public string strB;
public virtual void modifyUI_B()
{
Console.WriteLine("I am B");
}
}
一个继承B的子类A
class A:B
{
public A()
{
}
public string strA = "";
public void show_UI_A()
{
Console.WriteLine("I AM A_1");
}
}
我们在主函数main里面写这样的代码:
B b = (new A()) as B;
Console.WriteLine("====================");
b.modifyUI_B();
// b.show_UI_A(); //无法使用
Console.ReadKey();
问题具体化后,就是实例化A后,A本身看到是具备B和A的全部特性,强制转化为B类型。那么B不再拥有A的成员。就无法调用A的方法Method_A_1().那么我原先的问题,就出来了,子窗体被实例化强制转化基窗体后,为啥子窗体的内容还是会呈现到界面上
================原因=================
断点调试后,发现原因是这样的。每当子类A实例化的时候,基类B的构造函数会先被执行一遍,然后才是子类A的构造函数被执行一遍,所以后期,即使你强制转化了成了基类,也是只你无权访问子类成员了。但是如果你的子类的显示在构造函数里被相应了,也同样会被显示出来。比如将面的demo该成这样:
public class B
{
public B()
{
}
public string strB;
public virtual void modifyUI_B()
{
Console.WriteLine("I am B");
}
}
class A:B
{
public A()
{
show_U1_A();
}
public string strA = "";
public void show_UI_A()
{
Console.WriteLine("I AM A");
}
}
static void Main(string[] args)
{
B b = (new A()) as B;
Console.WriteLine("====================");
b.modifyUI_B();
Console.ReadKey();
}
如果改成上面这种情况,即使我们转化创基类,其实A界面的内容也会被显示出来,因为它在构造函数里面已经被调用了。
然后如果我们还要修饰界面风格,我们可以b.modifyUI_B();可以了。这样两者的的效果就会被叠加显示。这就是为什么实际项目中,子窗体没实例化后强制为基窗体,界面子窗体的内容也能被显示的原因。就是在子类的构造函数上已经初始化了窗体要显示的内容。最后强制的到的基类窗体对象只是无法拥有子窗体的成员而已。
======下面扩展点重写基类的知识======
如果子类重写了基类的方法,然后实例化了子类,再强制转化为基类,那么调用方法响应的拥有时被重写后的方法。
如下:
public class B
{
public B()
{
}
public string strB;
public virtual void modifyUI_B()
{
Console.WriteLine("I am B");
}
}
class A:B
{
public A()
{
show_U1_A();
}
public string strA = "";
public void show_UI_A()
{
Console.WriteLine("I AM A");
}
public override void modifyUI_B()
{
Console.WriteLine("此方法被子类已经重写");
}
}
static void Main(string[] args)
{
B b = (new A()) as B;
Console.WriteLine("====================");
b.modifyUI_B();
Console.ReadKey();
}
那么我们在子类强制转化为基类后调用modifyUI_B()的时候,其实仍然是调用的子类重写的方法。
还有一点仍需注意的是,如果子类实例化后,转化为基类,然后再转化为子类,原来的特性就都回来了。
==============问题延伸===================
大家有没有想过,如果基类实例化后,强制转化为子类又会是什么情况呢?
请看代码:
public class B
{
public B()
{
}
public string strB;
public virtual void modifyUI_B()
{
Console.WriteLine("I am B");
}
}
class A:B
{
public A()
{
show_U1_A();
}
public string strA = "";
public void show_UI_A()
{
Console.WriteLine("I AM A");
}
public override void modifyUI_B()
{
Console.WriteLine("此方法被子类已经重写");
}
}
static void Main(string[] args)
{
B b = (new A()) as B;
Console.WriteLine("====================");
b.modifyUI_B();
Console.WriteLine("====================");
A a = new B() as A;
a.modifyUI_B();//注意了,会报错。因为a为null
a.show_UI_A();//注意了,会报错。因为a为null
Console.ReadKey();
}
我们可以看到,我们把一个基类实例化后,强制转化为子类的实例,不管你是调用了基类的方法还是子类的方法,都会报错。因为
基类强制转化为子类后,子类为null。所以无法调用成员。希望通过正反两方面让大家对继承类之间的成员调用有更清晰的认识。
大二开始就知道继承和接口什么的,以为自己看懂了,其实很多细节都不懂。。。
来源:oschina
链接:https://my.oschina.net/u/1455020/blog/617660