图解继承
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication21
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
bc.printf(); //BaseClass.printf.
DerviedClass dc = new DerviedClass();
dc.printf(); //BaseClass.printf.
dc.printf1(); //DerviedClass.printf1.
BaseClass bcdc = new DerviedClass();
bcdc.printf();//BaseClass.printf.
}
}
class BaseClass
{
public void printf()
{
Console.WriteLine("BaseClass.printf.");
}
}
class DerviedClass:BaseClass
{
public void printf1()
{
Console.WriteLine("DerviedClass.printf1.");
}
}
}
图解第一步
BaseClass bc = new BaseClass();
bc.printf(); //BaseClass.printf.
图解第二步
DerviedClass dc = new DerviedClass();
dc.printf(); //BaseClass.printf.
dc.printf1(); //DerviedClass.printf1.
图解第三步
BaseClass bcdc = new DerviedClass();
bcdc.printf();//BaseClass.printf.
通过上面三个步骤,我们可以清楚在创建对象时,如何在系统中划分内存空间。接下来在分析,new关键字。
图解new
new关键字有三种应用场景:
1. 创建对象:如 BaseClass bc=new BaseClass();
2. 泛型约束。(后期介绍)
3. 隐藏基类成员、
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication21
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
bc.printf(); //BaseClass.printf.
DerviedClass dc = new DerviedClass();
dc.printf(); //DerviedClass.printf.
BaseClass bcdc = new DerviedClass();
bcdc.printf();//BaseClass.printf.
}
}
class BaseClass
{
public void printf()
{
Console.WriteLine("BaseClass.printf.");
}
}
class DerviedClass:BaseClass
{
public new void printf()
{
Console.WriteLine("DerviedClass.printf.");
}
}
}
改造第一节的代码,基类和派生类都有printf()方法,因为第一节有分三步进行图解,所以如上代码,图解原理和第一节差不多,这里不再阐述。
new关键字在代码子类成员中使用,显示隐藏了从基类继承的成员。如果不使用new,代码编译将会有警告,但不影响输出,系统自动帮我们加上new.
具有BaseClass类型的对象访问BaseClass类型的成员,具有DervicedClass类型的变量首先访问DerviceClass的成员,然后在考虑访问BaseClass的成员
可以参考MSDN
图解virtual,override
当类中成员被标识为virtual时,它可以被子类重写实现。子类重写需要使用override关键字。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication21
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
bc.printf(); //BaseClass.printf.
DerviedClass dc = new DerviedClass();
dc.printf(); //DerviedClass.printf.
BaseClass bcdc = new DerviedClass();
bcdc.printf();//DerviedClass.printf.
}
}
class BaseClass
{
public virtual void printf()
{
Console.WriteLine("BaseClass.printf.");
}
}
class DerviedClass:BaseClass
{
public override void printf()
{
Console.WriteLine("DerviedClass.printf.");
}
}
}
图解第一步
BaseClass bc = new BaseClass();
bc.printf(); //BaseClass.printf.
图解第二步
DerviedClass dc = new DerviedClass();
dc.printf(); //DerviedClass.printf.
图解第三步
与第一节第三步中内存图进行对比,这里可以看出new和virtual,override的区别。
BaseClass bcdc = new DerviedClass();
bcdc.printf();//DerviedClass.printf.
总结:
可以尝试把子类的override去掉,这时编译将会有警告,子类和父类有同名的方法printf,并且子类没有显示标识new或override。系统将自动使用new来隐藏父类的printf,这就回到了第一节第三步的图。
当使用基类变量来保存子类对象时,因为在内存中划分的区域并没有足够空间保存子类的成员,所以截断了,输出的只是基类自己的实现。
使用override后,子类重写类基类的方法,而不是建立一个新的printf。所以当基类变量保存子类对象时,有空间存储,这里输出的就是子类重写后的实现。