好久没来了,来看看,顺便讨论个简单问题

jedliu 2009-09-27 05:48:51
今天无聊,来CSDN转,发现一个JAVA关于继承的帖子:
http://topic.csdn.net/u/20090924/10/49392984-A2E8-45C5-ADA2-85CF910197E0.html

看了看觉得有点意思,我虽然做了几年程序了,但这种基础的问题除了面试的时候很少去关注!

动手做了以后发现,结果居然和他JAVA的不同!
我没做过JAVA,所以不明白JAVA里的继承是怎么样的,但总觉得不应该和C#差别太多吧!

后来自己在VS2005上建的一个控制台程序,编了个继承方面的测试类:

class Father
{
public Father()
{
Console.WriteLine("Father...");
}

private string GetName()
{
return "Father Name";
}

public string Move()
{
return "West";
}

public void Call()
{
Console.WriteLine(String.Format("This is {0}, and go {1}", GetName(), Move()));
}

public virtual void MyFunc(string str)
{
Console.WriteLine("{0} in Base", str);
}
}

class Child : Father
{
public Child()
{
Console.WriteLine("Children...");
}

private string GetName()
{
return "Children Names";
}

public string Move()
{
return "Far East";
}

public new void MyFunc(string str)
{
base.MyFunc(str);
Console.WriteLine("{0} in Derived", str);
}

public int ChildAge = 0;
}


static void Main(string[] args)
{
Father B = new Father();
B.MyFunc("BBB");
Console.WriteLine("-------------------------");

Child A = new Child();
B = A;//B的引用指向A
A.MyFunc("AAA");
Console.WriteLine("-------------------------");


B.MyFunc("BBB1");
Console.WriteLine("-------------------------");

Father C = new Child();
C.MyFunc("CCC");

Console.WriteLine("");
Console.WriteLine("");

Father hiren = new Father();
hiren.Call();

Child heria = new Child();
heria.Call();

Father newHi = heria;
newHi.Call();
}


各位先猜下结果是什么样的!反正我开始是想错了!看来自己理解还是不深,所以来这里和大家讨论下!



运行结果:

Father...
BBB in Base
-------------------------
Father...
Children...
AAA in Base
AAA in Derived
-------------------------
BBB1 in Base
-------------------------
Father...
Children...
CCC in Base


Father...
This is Father Name, and go West
Father...
Children...
This is Father Name, and go West
This is Father Name, and go West

public new void MyFunc(string str)这个方法的修饰符是new,当改成override的时候,上面结果会不同:
Father...
BBB in Base
-------------------------
Father...
Children...
AAA in Base
AAA in Derived
-------------------------
BBB1 in Base
BBB1 in Derived
-------------------------
Father...
Children...
CCC in Base
CCC in Derived

new的作用是告诉编译器,这个方法是全新的,和父类完全没关系,而上面结果不同的地方恰恰是父类型的对象在调用。我感觉就像是家里,儿子和老爹一样做生意,但他如果开创了全新的生意(new),那么老爹在做事的时候完全和儿子没关系,只需打理自己的生意。但如果是override,就成了子承父业,那么老爹做事就会提携帮助儿子。

还有一个问题,有朋友可能发现了:
B = A;//B的引用指向A
...
B.MyFunc("BBB1");
以及下面的:
Father newHi = heria;
newHi.Call();

这时候调用B或newHi,出来的结果不会涉及构造函数的部分,尽管构造函数里也有输出。
这里我不知道原因,唯一能想到的就是其他地方都是通过new Child()这种标准的创建对象的方式来做的,这里没有,所以也不会经过构造函数中的处理,它只是一个空对象,然后接受了一个已有对象而已。

很惭愧,做了几年了,这些基础东西还是没完全了解!
不知道这些理解对不对,欢迎大家批评指教!
...全文
165 21 打赏 收藏 举报
写回复
21 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
jedliu 2009-11-26
这里是故意隐藏的,一是为了查看和new有没有区别;二是为了查看在隐藏后,通过父类实例调用有什么不同。

[Quote=引用 18 楼 oasistree 的回复:]
C# codeclass Child : Father
{public Child()
{
Console.WriteLine("Children...");
}privatestring GetName()
{return"Children Names";
}publicstring Move()// 这里有问题,这里就应该用new,否则会有无声无息的隐藏父类方法 {return"Far East";
}publicnewvoid MyFunc(string str)
{base.MyFunc(str);
Console.WriteLine("{0} in Derived", str);
}publicint ChildAge=0;
}
有两种应用,根据需要来选用,一种是复写父类,一种是隐藏父类(我认为永远也不应该无声息的隐藏),两者都可以通过base来调用父类得实现,不同的是复写时(override)时父类的实列调用的也是子类的实现(只有在子类中可以通过base才可能调用到父类的实现),而隐藏父类实现时,谁的实例调用谁的实现。
    所以运用场合就是父类在设计时就计划到子类中可能有新的实现,而且这个实现更具有应用价值,在这种情况下就应该用复写。
    而在不确定父类是否在子类中有新的实现,而且父类本身的实现就很有应用价值,在子类中又必须要有新的实现,这种情况下就可能用到隐藏。
[/Quote]
  • 打赏
  • 举报
回复
oasistree 2009-10-15
如果不显示的隐藏父类方法,实际上在编译的时候会产生一个警告,我认为把这个定为一个错误都不过分。因为Explicitly is better than implicitly, 这是Python的一条哲学。其实C#把这个哲学应用的也很好,不像C++你一眼还看不出来那个类是抽象类。有时候多花一点字把问题描述的更清晰直观了明了了也值。
虽然程序语言在往自然语言的方向靠,但是程序语言的基础应用是用来描述逻辑的,描述逻辑应该越清楚越好。在描述需要模糊描述的创造性是模式时应该有另外一套东西。
  • 打赏
  • 举报
回复
oasistree 2009-10-15
[Quote=引用 6 楼 wuyq11 的回复:]
派生类必然具有基类的所有成员所以派生类可以毫无疑问地转换为基类
override关键字修饰符的方法是对基类中同名方法的新实现,基类中的同名方法必须声明为virtual或abstract类型。给基类中的方法添加virtual关键字表示可以在派生类中重写它的实现。
new修饰符用于显式隐藏继承自基类的成员,如果派生类成员与基类成员名称相同,new会将派生类成员识别为一个全新成员。
virtual定义为支持多态,用于对一个类中可修改的方法的声明,派生类类可以使用override关键字自由实现各自的虚拟方法
[/Quote]
其实我也是这个意思,通俗一点说复写是多态,而隐藏是一种补救措施,两者都通过base保留的调用父类实现的可能,这样就达到了建模流程上的全部实现,所以C#牛就牛在这。我以前对C#有抵触,因为它是微软的东东,但用了以后发现它在语言的概念模型层面上确实很牛鼻,不过它也是踩在巨人的肩膀上实现的,还NN的申请了那么多专利,好多概念就是换个词而已
  • 打赏
  • 举报
回复
oasistree 2009-10-15

class Child : Father
{
public Child()
{
Console.WriteLine("Children...");
}

private string GetName()
{
return "Children Names";
}

public string Move() // 这里有问题,这里就应该用new,否则会有无声无息的隐藏父类方法
{
return "Far East";
}

public new void MyFunc(string str)
{
base.MyFunc(str);
Console.WriteLine("{0} in Derived", str);
}

public int ChildAge = 0;
}

有两种应用,根据需要来选用,一种是复写父类,一种是隐藏父类(我认为永远也不应该无声息的隐藏),两者都可以通过base来调用父类得实现,不同的是复写时(override)时父类的实列调用的也是子类的实现(只有在子类中可以通过base才可能调用到父类的实现),而隐藏父类实现时,谁的实例调用谁的实现。
所以运用场合就是父类在设计时就计划到子类中可能有新的实现,而且这个实现更具有应用价值,在这种情况下就应该用复写。
而在不确定父类是否在子类中有新的实现,而且父类本身的实现就很有应用价值,在子类中又必须要有新的实现,这种情况下就可能用到隐藏。
  • 打赏
  • 举报
回复
zhoudashu 2009-10-15
基础很重要啊,我也要打基础啊
  • 打赏
  • 举报
回复
ws_hgo 2009-10-15
先看看
  • 打赏
  • 举报
回复
abclihongzhi 2009-10-15
学习了~~~~~
  • 打赏
  • 举报
回复
南三方 2009-10-15
关注中,接分
  • 打赏
  • 举报
回复
wanbotang 2009-10-15
其实就是一些基础,任何书在将多态的时候都有讲,
还有就是具体哪个重写成员被调用取决与对象的类型,而new显式隐藏或者没有new(使用相同的名称和签名)的成员调用则取决于变量的类型,
再说一点,如果再从Child类继承一个“孙子”的话,则隐藏的成员讲不被继承,“孙子”继承“爷爷”的那个。
  • 打赏
  • 举报
回复
freewind0521 2009-10-15
看不太懂
  • 打赏
  • 举报
回复
jedliu 2009-10-14
确实有点乱,想说的太多,但又怕大家不耐烦!
总的来说有两点:
1.那个JAVA程序的执行结果,因为从C#来执行看,结果完全不一样;
2.讨论关于继承方面的问题。主要是基类和子类方法的关系。

[Quote=引用 9 楼 lovelan1748 的回复:]
接分,描述得不太通俗了,虽然例子简单,看完一遍找不出楼主想说什么问题
[/Quote]
  • 打赏
  • 举报
回复
yuzhouhuo 2009-10-10
留名关注
  • 打赏
  • 举报
回复
lovelan1748 2009-10-10
接分,描述得不太通俗了,虽然例子简单,看完一遍找不出楼主想说什么问题
  • 打赏
  • 举报
回复
SQL77 2009-10-10
[Quote=引用 6 楼 wuyq11 的回复:]
派生类必然具有基类的所有成员所以派生类可以毫无疑问地转换为基类
override关键字修饰符的方法是对基类中同名方法的新实现,基类中的同名方法必须声明为virtual或abstract类型。给基类中的方法添加virtual关键字表示可以在派生类中重写它的实现。
new修饰符用于显式隐藏继承自基类的成员,如果派生类成员与基类成员名称相同,new会将派生类成员识别为一个全新成员。
virtual定义为支持多态,用于对一个类中可修改的方法的声明,派生类类可以使用override关键字自由实现各自的虚拟方法

[/Quote]
  • 打赏
  • 举报
回复
jedliu 2009-10-10
看来写太长了哈!
  • 打赏
  • 举报
回复
wuyq11 2009-09-27
派生类必然具有基类的所有成员所以派生类可以毫无疑问地转换为基类
override关键字修饰符的方法是对基类中同名方法的新实现,基类中的同名方法必须声明为virtual或abstract类型。给基类中的方法添加virtual关键字表示可以在派生类中重写它的实现。
new修饰符用于显式隐藏继承自基类的成员,如果派生类成员与基类成员名称相同,new会将派生类成员识别为一个全新成员。
virtual定义为支持多态,用于对一个类中可修改的方法的声明,派生类类可以使用override关键字自由实现各自的虚拟方法
  • 打赏
  • 举报
回复
panzhaojl 2009-09-27
汗 研究了半天。
  • 打赏
  • 举报
回复
mynameishuchao 2009-09-27
了解线程堆栈
内存分配,及继承的特性
  • 打赏
  • 举报
回复
xiaonanpiao 2009-09-27
private string GetName()
{
return "Children Names";
}
这个可以直接返回么?应该是这样的吧!
private string GetName();
public string A
{
get{ return "Children Names";}
}
  • 打赏
  • 举报
回复
阿牛138588 2009-09-27
private string GetName()
{
return "Children Names";
}

这个是private的。。。所以调用时实际上调用的是父类方法。不然就不会这样
  • 打赏
  • 举报
回复
加载更多回复
相关推荐
发帖
C#
加入

10.7w+

社区成员

.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
申请成为版主
帖子事件
创建了帖子
2009-09-27 05:48
社区公告

让您成为最强悍的C#开发者