读书人

父类句柄指向派生类范例时句柄的成员

发布时间: 2013-08-09 15:16:24 作者: rapoo

父类句柄指向派生类实例时,句柄的成员指向父类还是子类
using System;

class A
{
public int n =1;
public void showinfo()
{
System.Console.Write("some information aaa");
}

public virtual void showage()
{
System.Console.Write("13");
}

}

class B:A
{
//public int n =1;


public new void showinfo()
{
System.Console.Write("some information bbb");
}

public override void showage()
{
System.Console.Write("15");
}

public void getname()
{
System.Console.Write("name");
}
}


class Program
{
public static void Main()
{
A a1 = new B();//这里是实例化A,根据没有实例化B
a1.showinfo();//请问是执行的父类showinfo()还是派生的showinfo();为什么?我用new隐藏了父类同名方法,为什么测试得到这里还是执行的父类方法。a1.showage();
a1.getname();
}
}




继承的方法
[解决办法]
父类引用指向派生类实例时
除了virtual成员 通过父类引用 只能获取父类的成员

new的作用是为了隐藏父类的同名方法 隐藏不代表“去除”
class A
{
public void AA()
{
}
}

class B:A
{
public new void AA()
{

}
}

A a = new B();
a.AA(); //父类的

B b = new B();
b.AA(); //派生类的

[解决办法]
在很久很久以前,我使用c和汇编语言来开发国产的大型程控交换机的话务台系统,那时候还刚刚又“面向对象技术”这种东西(国外也刚刚开始出现其成熟的理论,例如OMT),我们自己使用不支持OOPL的编程语言来来“委派地”模拟OOPL技术,就是这样“子类对象内部有一个指针去指向父类对象”的。因为我们做不了编译器,只能用比较低级的手段模拟人家OO编程。

但是这中模拟是有害的,因为你的脑子里毕竟有着一大堆结构化、冗余的东西干扰你的设计到代码的实现。如果你使用一种OOPL语言,就不要再去以为“子类对象内部有一个父类对象”这种东西,子类对象“就是”一个父类对象,而不是委派。
[解决办法]
因为你根本没有任何OO设计的经验,所以体会不了函数重写和隐藏的使用场景,这才有这样的疑问。

即便你记住了什么一些“规则”,又有什么用呢。对你来说,这只是一个纸上谈兵的魔术而已。

既然你提问,何必掩饰自己的问题所在。不懂装懂反倒让人觉得可笑。



我们先不看函数的重写,看另一个你肯定知道的问题,以及它们之间的关系。

我们知道在OO语言中(包括C#,也包括别的语言),第一要务是封装。

比如
class A
{
int id;
}
这里id是一个int类型的私有变量。
这个代码等价
class A
{
private int id;
}
如果我们希望外部访问id,需要这么写:
class A
{
public int id;
}
是不是很简单,很容易理解。
然而,我想告诉你的是一个原则,这个原则你必须记住,那就是OO语言强调封装,也就是说,为了让编写被调用者代码的开发者可以很容易地预见调用者的调用行为,它的设计是保守的。

我们再看这样一个类
class A
{
public void foo() { ... }
}
它实际上等价这样的代码:
class A
{
public sealed void foo() { ... }
}
它表示编写A这个类的开发者并没有允许继承这个类的开发者去重写这个方法。

你要知道,继承这个类的开发者(调用者)去重写一个方法会改变这个类的行为,就好比调用者去操作一个私有变量会在类设计者的预料之外改变对象的状态一样。

没有预料地使用代码,是程序出现故障的重要来源。

为此,C#和大多数OO语言一样,如果你希望你的方法被重写,你必须显式地使用virtual关键字。就好比你希望调用者操作一个对象的成员变量,必须显式地使用public一样。

好了,我们明白了,函数重写的目的使它的设计者改变继承基类的行为。

废话,如果说写了半天代码,这代码不起作用,那还重写个屁。

因此如果一个方法被重写,那么无论是
A a = new B(); a.foo();
还是 B a = new B(); b.foo();
都是调用的是B中定义的那个方法。

然后我们再说new。这个关键字允许你在另一个类中定义一个和继承的基类完全无关,但是同名的方法。我告诉你它的作用了,设想一下它的使用场景——这只有在极罕见的情况下才被用到,大多数情况下,你有什么理由用一个函数名去定义两个毫无关系的方法呢?

既然new是定义一个和继承基类毫无关系的方法。
A a = new B(); a.foo(); 显然不会调用这个new的方法——我说了,它和A毫无关系。
[解决办法]
在面向对象设计中,类似

public new void AA()
这种东西是完全“毁三观”的。在面向对象系统设计中,必须支持继承和对消(重写)。

这个new写法,我非常明确地说大概1几年前它“就是从c++中移植的糟粕”。好在c#中这类东西非常稀少。我相信如果2010年微软才来发明c#语言,绝对不会支持这种东西。

你要知道,既然你明明知道子类跟父类的AA方法冲突,你为什么要特意弄一个冲突的名字呢?你为什么不能把子类中的这个方法起名叫做AA1()呢?

严重地破坏了OOAD编程规范的东西,这类new语法,幸好在c#中非常稀少。不然我们早就不用c#语言了!

读书人网 >C#

热点推荐