随笔-65  评论-1102  文章-2  trackbacks-39
      面向对象的三大特性之一就是继承,而使用继承的时候,必须要把握好的就是父类与子类之间的关系..避免使用过多的父子层次..说到关系,最先接触到的则是构造函数..为什么??OK.看下面的代码,大部分的公司面试的时候可能都会有这么一道类似的题..考的目的就是看你对构造函数的理解..

    
 1class a
 2{
 3    public a(int i )
 4    {
 5        Console.WriteLine( "父类初始化" + i );
 6    }

 7    
 8}

 9
10class b:a
11{
12    public b()
13    {
14        Console.WriteLine( "继承类初始化" );
15    }

16    
17}

18
19static void Main(string[] args)
20{
21    b bb = new b();
22}



     看过上面简单的代码,只是段简单的类继承而已..但是如果没有使用过继承,或者没遇到过类似代码..第一反应可能,输出的结果应该是:继承类初始化..

     但是事实恰恰相反.这段代码不会通过编译..报错: 重载“a”方法未获取“0”参数...先来看一下class b的执行过程,当你声明它的时候,会先调用父类
a的构造,再调用子类b自己的构造函数..因为我们的a构造函数必须传递一个int参数,而b构造函数不需要传递参数.这样就造成了矛盾,在使用class b时,系统要先构造出a来,而a的构造函数需要一个参数,此时子类b的构造函数并没有满足a的构造函数,.所以才造成这样的错误..

     解决的办法有很多,最简单的办法就是,可以给父类的构造函数提供一个无参数的构造函数..

 1class a
 2{
 3    public a(int i )
 4    {
 5        Console.WriteLine( "父类初始化" + i );
 6    }

 7    
 8    public a(){
 9        Console.WriteLine( "父类初始化" );
10    }

11
12}

     把class a添加了这么一个无参数的构造函数后,错误就没有了..class b可以被正常的实例化..但是这样的情况并不是通用..当你需要在子类中使用父类中的方法,而父类的方法需要根据有参数的构造函数进行初始化某些属性的时候..这个简单的办法就失去了意义...比如,一个父亲,一个儿子,根据火星人类研究基地的报告,一般儿子的IQ是受父亲IQ的影响的,即父亲的IQ直接影响了儿子的IQ...这个时候这个类的设计代码可以如下..

    
 1using System;
 2
 3namespace Overloading
 4{
 5    /// <summary>
 6    /// Class1 的摘要说明。
 7    /// </summary>

 8    class Class1
 9    {
10        /// <summary>
11        /// 应用程序的主入口点。
12        /// </summary>

13        [STAThread]
14        static void Main(string[] args)
15        {
16            b bb = new b(22);
17            Console.WriteLine( "父类的IQ:" + bb.a_IQ );
18            Console.WriteLine( "子类的IQ:" + bb.IQ );
19        }

20    }

21    
22    class a
23    {
24        //public a(){}        这个可以根据情况添加
25        
26        public a( int i ) 
27        {
28            Console.WriteLine( "父类初始化" + i );
29            this._IQ = i;
30        }

31        
32        private int _IQ;
33        public int IQ
34        {
35            get return _IQ; } 
36            set { _IQ = value; } 
37        }

38    }

39    
40    class b:a 
41    {
42        public b():base(0
43        {
44            Console.WriteLine( "继承类初始化" );
45            this._IQ = 1;
46        }

47        
48        public b(int i):base(i) 
49        
50            Console.WriteLine("子类初始化" + i);
51            this._IQ = i;
52        }
 
53        
54        private int _IQ;
55        new public int IQ                    //在这里覆盖了父类的IQ值
56        {
57            get return this._IQ + base.IQ; } //子类的IQ值是父类+子类的IQ
58            set { _IQ = value; }  
59        }

60        
61        public string a_IQ
62        {
63            get return base.IQ.ToString(); } 
64        }

65        
66    }

67}

68

代码运行的结果:


     上面的代码编译后,从结果可以看出来..继承带来了方便的同时,无形中也增加了类设计的复杂度和耦合度..我想,这个也是为什么大多数书籍都推荐我们,使用继承的时候尽量不要有太多的层次关系的原因之一吧..这个就好像,一个父亲有了N个儿子之后,对于国家(框架)和父亲来说,负担都是太大太大了..要照顾的有N个..所以,合理有效的使用继承还是需要研究.琢磨,试验的..明白了上面两个小例子之后,再面试的时候碰到类似的问题,就可以避免失分咯..何况这个题目是如此的简单..这道要是做错了..嘿嘿...后果可想而知哦....

posted on 2006-01-24 16:52 难得一蠢 阅读(2057) 评论(11)  编辑 收藏 所属分类: C#.NET小蠢笔记

评论:
#1楼  2006-01-24 17:17 | xiao_p      
继承真的是很烦燥的东西,我现在竟然都不会做这个test…………

晕死了…………

那个24 怎么来的???
还没有看明白!!~~~~

  回复  引用  查看    
#2楼 [楼主] 2006-01-24 17:27 | 难得一蠢      
看下面的代码..主要是用子类的IQ + 父类的IQ..因为在子类构造的时候,父类也被构造了..所以,可以使用父类中的IQ..

54 private int _IQ;
55 new public int IQ //在这里覆盖了父类的IQ值
56 {
57 get { return this._IQ + base.IQ; } //子类的IQ值是父类+子类的IQ
58 set { _IQ = value; }
59 }
60
  回复  引用  查看    
#3楼  2006-01-24 17:53 | xiao_p      
唉 , 不知道怎么的就把Console.WriteLine( "子类的IQ:" + bb.IQ );
的输出看成了24 —………………

于是就苦苦的寻找哪里来的2? 还没有想到看错的可能性……

细节决定一切……
古人诚不欺我……

  回复  引用  查看    
#4楼  2006-01-25 02:00 | torome      
48 public b(int i):base(i)
49 {
50 Console.WriteLine("子类初始化" + i);
51 this._IQ = i;
52 }
不知道48行中的base(i) 是什么意思?
能解释一下吗?谢谢!
  回复  引用  查看    
#5楼 [楼主] 2006-01-25 08:03 | 难得一蠢      
To: torome

这里的base代表着父类..base(i)意思是,在子类初始化的时候,用base关键把父类也初始化了..如果不能满足父类的构造函数..子类也就无法被构造出来...所以需要用base(i)把父类构造..
  回复  引用  查看    
#6楼  2006-01-25 10:08 | torome      
那base(i)中的参数i,是不是指构造函数中的参数?
  回复  引用  查看    
#7楼  2006-01-25 11:43 | Wu.Country@侠缘      
昏。。。。。。。。。。。
理解继承要从两个方面上入手。
1、对象的关系:
就是说子对象一定是父对象。这和我们实际生活是一样的,所以在写类的时候一定要注意。如果你非要从一个飞机类继承出家用小汽车类,那只会是自找麻烦。
2。类的内存分配:
所有的类都是先构造父类的,所以在你写子类的构造函数时,一定得考虑一下:这时父类是否有分配内存,否则是不能通过编译的。我遇到一面试题就是:能否隐式的从父类实例化一个子类。答案是不能通过编译(与阁主的第一例类似)。如果不好处理内存分配的时候,可以考虑一下用接口。

这里的问题:
get { return this._IQ + base.IQ; } //子类的IQ值是父类+子类的IQ
这是一个方法(特殊方法,也就是属性),返回两个值的和,当然是44了,但子类与父类成员变量:_IQ;其实它的值还是没变(跟踪调试一下就明白了)。这里还不如写一个Add函数来的方便,而且好理解,本质是把子类的_IQ与父类的_IQ加了一次。



  回复  引用  查看    
#8楼 [楼主] 2006-01-25 12:15 | 难得一蠢      
To: torome
呵呵,看看上面 Wu.Country@侠缘 的回答就知道了..

这里的base是指父类..base(i)是调用父类的构造函数..
public b(int i):base(i) 和 public b():base(0) 这个两个地方都可以看出来..无论怎么构造子类,都需要先满足父类的构造函数才可以...
  回复  引用  查看    
#9楼  2006-01-25 23:38 | 小陆      
继承不是不推荐使用,而是很多人在滥用继承。具有父子关系的两个类一定要在实际上存在明确的所属关系,只不能只是为了复用一段代码就随意的继承。
“Wu.Country
就是说子对象一定是父对象。这和我们实际生活是一样的,所以在写类的时候一定要注意。如果你非要从一个飞机类继承出家用小汽车类,那只会是自找麻烦。”
这句话说的不错。
  回复  引用  查看    
#10楼  2006-01-28 10:28 | dfdsf [未注册用户]
帮顶!

http://www.source520.com

站长开发推广同盟 站长朋友的终极驿站
同时拥有海量源码电子经典书籍下载

http://www.source520.com/search/search.asp

"编程.站长"论坛搜索引擎-----为中国站长注入动力!
  回复  引用    
#11楼  2006-05-16 22:41 | 航天奇侠      

继承很大程度上,不是为了使用子类来复用基类。而是通过基类来多态调用子类。

因此,我觉得,如果从这个角度来设计基类,会比复用的思想要好。

  回复  引用  查看    

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-01-24 16:57 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: