虚方法
virtual 关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。例如,此方法可被任何继承它的类重写。
当类中的方法声明前加上了virtual修饰符,我们称之为虚方法,反之为非虚。
若希望或预料到基类的这个方法在将来的派生类中会被重写(override ),则此方法必须被声明为 virtual。
调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。
默认情况下,方法是非虚拟的。不能重写非虚方法。
virtual 修饰符不能与 static、abstract, private 或 override 修饰符一起使用。
除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。
· 在静态属性上使用 virtual 修饰符是错误的。
· 通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。
虚方法的定义形式
virtual 修饰符 返回的数据类型方法名(参数表)
{
方法体
}
对于非虚的方法,无论被其所在类的实例调用,还是被这个类的派生类的实例调用,方法的执行方式不变。而对于虚方法,它的执行
方式可以被派生类改变,这种改变是通过方法的重载来实现的。
虚方法的重载形式
override 修饰符 返回的数据类型方法名(参数表)
{
方法体
}
override 重写继承自基类的 virtural 方法,可以理解为拆掉老房子,在原址上建新房子,老房子再也找不到了(基类方法永远调用不到了)。
New和override的异同
new和override的相同点:
都可以对基类成员进行隐藏,都可以用base关键字调用基类的成员
new和override的不同点:
用override的基类的方法必须要用virtual,而new不必要
本质区别在于当派生类对象作为基类类型使用时,override 的执行派生类方法,new 的执行基类方法。如果作为派生类类型调用,则都是执行 override 或 new 之后的。
override 重写继承自基类的 virtural 方法,可以理解为拆掉老房子,在原址上建新房子,老房子再也找不到了(基类方法永远调用不到了)。
new 隐藏继承自基类的 virtual 方法,老房子还留着,在旁边盖个新房,想住新房住新房(作为派生类对象调用),想住老房住老房(作为基类对象调用)。
当派生类中出现与基类同名的方法,而此方法前面未加 override 或 new 修饰符时,编译器会报警告,但不报错,真正执行时等同于加了 new。
下面是代码实现:
public interface I_9_A
{
int Age { get;set;}
string GetName();
string GetPwd();
}
/// <summary>
/// 下面这个类继承了A接口,并实现了里面的全部成员
/// </summary>
public class I_9_L_1 : I_9_A
{
protected int age;
protected string name;
protected string pwd;
public I_9_L_1()
{
age = 28;
name = "提高班";
pwd = "tgb";
}
public int Age
{
get { return age; }
set { age = value; }
}
public string GetName()
{
return name;
}
public string GetPwd()
{
return pwd;
}
}
public class I_9_L_2 : I_9_L_1
{
public new string GetName()
{
return ":" + name;
}
public new string GetPwd()
{
return "密码:" + pwd;
}
}
/**当我们看了上面的演示以后会发现一个很严重的问题,
* 我们明明就调用的2这个类,可为什么方法却依然是1哪个类的呢?
* 原因就在2这个类虽然是复写了1类中的方法,但是他并没有去改写1类中的方法
**/
///
/// <summary>
/// 下面这个类继承了A接口,并实现了里面的全部成员
/// </summary>
public class I_9_L_3 : I_9_L_1
{
protected int age;
protected string name;
protected string pwd;
public I_9_L_3(int a, string n, string p)
{
age = a;
name = n;
pwd = p;
}
public int Age
{
get { return age; }
set { age = value; }
}
public virtual string GetName()
{
return name;
}
public virtual string GetPwd()
{
return pwd;
}
}
public class I_9_L_4 : I_9_L_3
{
public I_9_L_4(int a, string n, string p)
: base(a, n, p)
{
age = a;
name = n;
pwd = p;
}
public override string GetName()
{
return "我是:" + name;
}
public override string GetPwd()
{
return "密码是:" + pwd;
}
}
/**
* 其实这个例题理解起来不难的,首先我们知道他整个的运行顺序
* 然后就是,如果发现不是虚方法,那么就直接调用了,但是如果是他就会继续往下找,一直找到不是虚的位置.
*
* 我们这个例题说完了,不知道你有没有想起我们前面说过的一个问题,就是显示实现的无法使用修饰符,
* 既然不能使用修饰符,那virtual也没法用,难道显示实现的方法就不能使用虚方法了吗?
*
* 答案是否定的,呵呵
*
* 我们可以在这个显示实现中调用另一个方法嘛,哈哈,然后这个被调用的方法再是虚方法,我想法律不会不允许吧
* **/
///
/// <summary>
/// 下面这个类继承了A接口,并实现了里面的全部成员
/// </summary>
public class I_9_L_5 : I_9_A
{
protected int age;
protected string name;
protected string pwd;
public I_9_L_5(int a, string n, string p)
{
age = a;
name = n;
pwd = p;
}
public int Age
{
get { return age; }
set { age = value; }
}
public string GetName()
{
return name;
}
public string GetPwd()
{
return pwd;
}
}
public class I_9_L_6 : I_9_L_5,I_9_A
{
public I_9_L_6(int a, string n, string p)
: base(a, n, p)
{
age = a;
name = n;
pwd = p;
}
public string GetName()
{
return "我是:" + name;
}
public string GetPwd()
{
return "密码是:" + pwd;
}
}
}
---------------------------原文参考CSDN和天轰穿视频