none
关于非默认构造函数问题 RRS feed

  • 问题

  • 声明一个基类非默认构造函数和一个派生类构非默认造函数,如何实例化一个派生类对象,把它的i参数指向,基类参数i?最好能演示一下派生类参数如何与基类参数关联上?

    类及非默认构造函数声明代码如下:

     public class MyBaseClass
        {
            public MyBaseClass(int i)
            {
            }
        }
        public class MyDerivedClass : MyBaseClass
        {
            public MyDerivedClass(int i, int j)
                : base(i)
            {
            }
        }


    万物皆变,规则永恒。
    2011年3月3日 7:04

答案

  • 同时还要指出你给我的实例做出如下修改就更能说明base指定对从基类到派生类构造函数的执行序列的执行的控制,你的代码修改如下:

    //基类
    public class MyBaseClass
    {
      public int ID; //有一个ID属性//有一个ID属性

    //基类默认构造函数
      public MyBaseClass()
    {

    }
      //父类构造自己的属性 ID
      public MyBaseClass(int id )
      {
        ID = id;
      }
    }

    //子类
    public class MyDerivedClass : MyBaseClass
    {

      public string Name; //有一个Name属性

      public MyDerivedClass(int id, string Name)
       : base(id) //把初始化id的工作交给基类,子类就不用再操心了
      {
        Name = name;//子类自己处理name
      }
    }


    //////测试代码
    MyDerivedClass subObj = new MyDerivedClass( 1, "Jack");
    MyDerivedClass subObj = new MyDerivedClass( 2, "Tom");

    这里面如果不在继承类里面指定base(id),那么构造函数的执行序列是这样的:

    先执行system.object.object()构造函数,然后执行MyBaseClass.MyBaseClass(),最后执行 MyDerivedClass(int id, string Name)。

    如果我们在派生类非默认构造函数中加了bese(id),那么构造函数的执行序列就按我们意愿设定的顺序执行了即如下:

    先执行system.object.object()构造函数,然后执行MyBaseClass.MyBaseClass(int id),最后执行 MyDerivedClass(int id, string Name)。

    这就是我说的关键字base的意义,(请注意我讨论的是意义不是用法,这是两回事)可通过关键字base指定基类构造函数初始化器改变构造函数执行序列是其意义之一,指定某一参数在基类中先行执行,减少派生类中构造函数的工作量和简化代码,这就是base的意义之二。


    万物皆变,规则永恒。
    2011年3月5日 6:26

全部回复

  • 您好,构造函数不能被继承,需要增加一个构造函数:

    public class MyDerivedClass : MyBaseClass
        {
            public MyDerivedClass(int i, int j)
                : base(i)
            {
            }

            public MyDerivedClass(int i)
                : base(i)
            {
            }
        }

    public class MyDerivedClass : MyBaseClass
        {
            public MyDerivedClass(int i, int j)
                : base(i)
            {
            }

            public MyDerivedClass(int i)
                : this(i, 0)
            {
            }
        }

    2011年3月3日 8:02
    版主
  • 谢谢,回答,但是你没明白我的意思,我说的不是继承的问题,我问的是演示一下,非构造函数基类与派生类参数如何引用的例子,就是派生类里面base(i)中的i和基类中的 i 之间的关系?
    万物皆变,规则永恒。
    2011年3月3日 8:39
  • 谢谢,回答,但是你没明白我的意思,我说的不是继承的问题,我问的是演示一下,非构造函数基类与派生类参数如何引用的例子,就是派生类里面base(i)中的i和基类中的 i 之间的关系?
    万物皆变,规则永恒。


    您好,并无直接关系,只是值传递,基类和派生类接收到 i 值后自行处理。

    您可写个测试类,设个断点,单步跟踪一下。

    2011年3月3日 8:56
    版主
  • 谢谢,回答,但是你没明白我的意思,我说的不是继承的问题,我问的是演示一下,非构造函数基类与派生类参数如何引用的例子,就是派生类里面base(i)中的i和基类中的 i 之间的关系?
    万物皆变,规则永恒。


    您好,并无直接关系,只是值传递,基类和派生类接收到 i 值后自行处理。

    您可写个测试类,设个断点,单步跟踪一下。

    谢谢,明白一些了,但是还有疑问:
    您的意思是不是同时引用一同个变量 i ,各自处理,而不是派生类从基类传递来的 i 值?那么派生类里还写个base(i)的意义何在?不写这个不派生类的i也能引用同一变量值吗?
    万物皆变,规则永恒。
    2011年3月3日 9:23
  • 在继承的层次结构中,子类必需调用基类的构造函数。

    即使您看到很多子类没有调用base,那是因为基类中包含有默认的构造函数(即不带参数的构造函数)。

    当基类中不存在默认的构造函数时,就需要调用base(*),这就是base(i)的意义,本例子中基类没有构造函数,所以需要指明。

    再给个知识点:如果在代码中不写构造函数,那么自动包含一个不带参数的构造函数,如果写了构造函数,则默认的构造函数需要显示声明。

    另外我上面说的各自处理,这是一种情况,根据设计的目的不同,也有可能只在基类中处理,在子类中可以继承处理后的结果。

    2011年3月3日 11:59
    版主
  • 在继承的层次结构中,子类必需调用基类的构造函数。

    即使您看到很多子类没有调用base,那是因为基类中包含有默认的构造函数(即不带参数的构造函数)。

    当基类中不存在默认的构造函数时,就需要调用base(*),这就是base(i)的意义,本例子中基类没有构造函数,所以需要指明。

    再给个知识点:如果在代码中不写构造函数,那么自动包含一个不带参数的构造函数,如果写了构造函数,则默认的构造函数需要显示声明。

    另外我上面说的各自处理,这是一种情况,根据设计的目的不同,也有可能只在基类中处理,在子类中可以继承处理后的结果。

    谢谢你的解答,但我对你的解答有不同看法,

    首先我们回到构造函数的本质,构造函数的根本目的是对类对象进行初始化设置,最基本的任务之一比如对一些变量进行初始赋值,通过非默认构造函数参数对变量赋值是一个途径,因此为了减少参数在派生类里参数代码的复杂性,尤其多个参数,可通过关键字base指定基类构造函数初始化器改变构造函数执行序列是其意义之一,指定某一参数在基类中先行执行,减少派生类中构造函数的工作量和简化代码,这就是base的意义之二。(假定上面例子里基类和派生类里的 int i 具有相同含义,当然也可以不同,就如你所说:并无直接关系,只是值传递,基类和派生类接收到 i 值后自行处理。)

    当然你说的也没错,如果没有默认构造函数只有非默认构造函数就需要调用base,但这我认为不是base的本质意义,因为不指定编译器会报错滴,因为编译器有其他构造函数就不会执行自建默认构造函数的工作,但是如果不指定它又不知道执行哪个非默认构造函数,当然找不到默认构造函数也不会按默认序列执行,这也正是我们想控制构造执行序列顺序的目的。

    不知道我理解的是否正确,还请指正。 


    万物皆变,规则永恒。
    2011年3月4日 17:31
  • //估计是两个相同数据类型的int参数,而且使用了毫无实际意义的i和j变量名,因此把你搞晕了。如果换一个角度你就很容易理解了:
    
    //基类
    public class MyBaseClass
     {
      public int ID; //有一个ID属性
    
      //父类构造自己的属性 ID
      public MyBaseClass(int id )
      {
        ID = id;
      }
     }
    
     //子类
     public class MyDerivedClass : MyBaseClass
     {
    
      public string Name; //有一个Name属性
    
      public MyDerivedClass(int id, string Name)
       : base(id) //把初始化id的工作交给基类,子类就不用再操心了
      {
        Name = name;//子类自己处理name
      }
     }
    
    
    //////测试代码
    MyDerivedClass subObj = new MyDerivedClass( 1, "Jack");
    MyDerivedClass subObj = new MyDerivedClass( 2, "Tom");
    --------------------------------------------------------------------------------
    信奎爷,无所畏惧! 
    2011年3月5日 4:44
  • 补充一下,在C#中,子类调用自己或自己基类的其它构造函数是有效的,也就是可以在构造时重用其它构造函数。

    但是如果是在C++中的话, 如果你在构造函数中调用其它任何构造函数的话。 表面上编译不会出错,但是实际运行后你会发现,调用其它构造函数是无效的!

    C++说,我们自立更生,别人不准插手! 哈哈^o^


    信奎爷,无所畏惧!!
    2011年3月5日 4:51
  • 呵呵,你举的例子就是我最后总结的意思,核心目的就是为了控制执行序列即构造函数执行顺序,你仔细看一下,谢谢你给出的实例。


    万物皆变,规则永恒。
    2011年3月5日 5:45
  • 同时还要指出你给我的实例做出如下修改就更能说明base指定对从基类到派生类构造函数的执行序列的执行的控制,你的代码修改如下:

    //基类
    public class MyBaseClass
    {
      public int ID; //有一个ID属性//有一个ID属性

    //基类默认构造函数
      public MyBaseClass()
    {

    }
      //父类构造自己的属性 ID
      public MyBaseClass(int id )
      {
        ID = id;
      }
    }

    //子类
    public class MyDerivedClass : MyBaseClass
    {

      public string Name; //有一个Name属性

      public MyDerivedClass(int id, string Name)
       : base(id) //把初始化id的工作交给基类,子类就不用再操心了
      {
        Name = name;//子类自己处理name
      }
    }


    //////测试代码
    MyDerivedClass subObj = new MyDerivedClass( 1, "Jack");
    MyDerivedClass subObj = new MyDerivedClass( 2, "Tom");

    这里面如果不在继承类里面指定base(id),那么构造函数的执行序列是这样的:

    先执行system.object.object()构造函数,然后执行MyBaseClass.MyBaseClass(),最后执行 MyDerivedClass(int id, string Name)。

    如果我们在派生类非默认构造函数中加了bese(id),那么构造函数的执行序列就按我们意愿设定的顺序执行了即如下:

    先执行system.object.object()构造函数,然后执行MyBaseClass.MyBaseClass(int id),最后执行 MyDerivedClass(int id, string Name)。

    这就是我说的关键字base的意义,(请注意我讨论的是意义不是用法,这是两回事)可通过关键字base指定基类构造函数初始化器改变构造函数执行序列是其意义之一,指定某一参数在基类中先行执行,减少派生类中构造函数的工作量和简化代码,这就是base的意义之二。


    万物皆变,规则永恒。
    2011年3月5日 6:26
  • 没看出哪有不同的看法。

    一个问题本就可以从不同的角度来解释。例如从语法,从设计的含义等等。您提到的简化代码,我上面有说明。

    不明白为什么要搞一个执行序列的名词出来,构造函数也是方法,也不过是调用不同的方法而已!

    既然您对构造函数有如此的了解,不明白您提问的目的?

    2011年3月5日 11:50
    版主
  • 呵呵,首先声明执行序列不是偶的发明,这是很多书籍上的提法。至于为啥提问就是因为看了这些书上的这一讲解中提到关键字base的使用,但又没有讲解的很详细,所以一头雾水,因此发问,经过各位的指点,我又反复结合书上的终于顿悟了base用法在构造函数执行序列中的实质意义,就是这样,我现在明白了,你说的不错,一个问题可以从不同角度解释,从函数的角度就是相关的函数之间的关系,但从高一些的角度是执顺序的关系,即执行序列的关系。我并不是否定或反驳你,(偶只是一个菜鸟,没有哪个水平,呵呵)你解释的更微观一些,书上讲解的更宏观一些,因此结合你的讲解,我才领悟的全面起来。所以这里要谢谢你,还希望以后多多指教。
    2011年3月5日 12:33
  • 指教不敢,一起讨论问题,共同进步。
    2011年3月5日 13:10
    版主
  • 指教不敢,一起讨论问题,共同进步。

    这算什么答案,文不对题。要标请标feiyun0112 建议的。不然请取消!
    2011年3月7日 10:35
    版主