写在前面:本文原来取名为《C#构造函数继承小结》,后来思索再三,感觉名字略有不妥,因为构造函数不存在继承一说,所以改名为现在的名字。
直接上例子,通过例子来学习知识,是我一贯的做法,呵呵。
//爷爷类
public class GrandfatherClass
{
public GrandfatherClass()
{
Console.WriteLine("Constructor of GrandfatherClass");
}
public GrandfatherClass(string from)
{
Console.WriteLine("Constructor of GrandfatherClass:{0}", from);
}
}
//父亲类
public class FatherClass:GrandfatherClass
{
public FatherClass()
{
Console.WriteLine("Constructor of FatherClass");
}
public FatherClass(string from)
{
Console.WriteLine("Constructor of FatherClass:{0}", from);
}
}
//小霸王类,我是小霸王,腰里别只鸡
public class MeClass : FatherClass
{
public MeClass()
{
Console.WriteLine("Constructor of MeClass");
}
public MeClass(string from)
{
Console.WriteLine("Constructor of MeClass:{0}", from);
}
}
static void Main(string[] args)
{
//类实例化
Console.WriteLine("类实例化,调用无参构造函数:");
MeClass me = new MeClass();
Console.WriteLine();
//类实例化,含参数
string from = "tiana0";
Console.WriteLine("类实例化,调用有参构造函数:");
MeClass me1 = new MeClass(from);
}
运行代码,得到以下结果:
通过对运行结果的分析,可以得出以下结论:
子类会从下往上(本例中的MeClass到FatherClass,再到GrandfatherClass)延继承关系依次调用父类的无参构造函数。记住:是无参的构造函数哦。所以,在MeClass类实例化时,不管自己调用的构造函数是有参的还是无参的,父类被调用的构造函数永远是无参的。所以两次实例化时,父类被调用的都是无参的构造函数。当然,执行时,就应该是从上往下(先是GrandfatherClass,再是FatherClass,最后才是MeClass)依次来执行构造函数的,所以结果中,父类的构造函数先于子类的构造函数被执行。这有点像:一旦有了难处,孩子就会去找父亲,父亲搞不定时,就得找德高望重的老爷子,老爷子搞定了,父亲自然也能搞定了,父亲搞定了,儿子还能搞不定它或者她(开个玩笑而已,比喻不当也别见怪)。
接下来,再做个小实验,将前面代码中的以下部分注释掉:
//public FatherClass()
//{
//Console.WriteLine("FatherClass Constructor:FatherClass()");
//}
你会发现,出现了编译错误,错误提示如下:
FatherClass不包含采用“0”个参数的构造函数。
为什么呢,哥们,快快道来。别急,在揭晓答案之前,还得做个实验,实验同样简单,首先取消对刚才代码的注释,再接着将以下部分注释掉:
//public FatherClass(string from)
//{
//Console.WriteLine("FatherClass Constructor:FatherClass({0})", from);
//}
你会发现,编译代码一切正常。
那到底是为什么呢(小沈阳说:为什么呢?),原因其实在前面已经解释过了,类会从下往上延继承关系依次调用父类的无参构造函数。当FatherClass的无参构造函数被注释后,这条通道自然就不存在了,当然会报错的嘛,至于FatherClass的有参构造函数注不注释掉,没有任何影响,因为调用的是无参的构造函数哦(再来哦~~一次)。
先写到这里,要睡觉了,亲。
补上一句,你还可以单步调试,跟踪代码走向,同样会得出以上结论。
前次,由于时间关系,便仓促地结束了此博文的书写。后来细细一想,感觉有必要补充一些没有表述到或者表述不清晰的知识点。
通过前文的表述,我们已了解到,子类会自动调用父类的无参构造函数。
对于这点,我们很容易联想到下面这个问题:子类会自动调用父类的无参构造函数,那么子类要是想调用父类的有参构造函数,又该怎么办呢?
要想回答这个问题,我们需要对前文所给的代码做个小小的修改,具体改动的代码如下:
public MeClass(string from)
: base(from)
{
Console.WriteLine("MeClass Constructor:MeClass({0})", from);
}
发现了吗?仅仅加上了代码“:base(from)”,这部分代码就是为了告诉编译器子类想调用的是父类的有参构造函数。很显然,FatherClass类要想调用GrandfatherClass类的有参构造函数,同样需要对代码做相同的修改,具体代码如下:
public FatherClass(string from)
: base(from)
{
Console.WriteLine("FatherClass Constructor:FatherClass({0})", from);
}
最后运行程序,得到以下结果:
对于结果,我就不解释了,大家可以结合代码进行一番简单的分析。
提到base关键字,我又想起了一个小问题,这个问题是我前段时间在阅读一个项目代码时想到的,当时代码中有如下一段代码(类似代码)。
//小霸王类,我是小霸王,腰里别只鸡
public class MeClass : FatherClass
{
public MeClass()
: base()
{
Console.WriteLine("MeClass Constructor:MeClass()");
}
}
其实就是在构造函数后加上了“: base()”,当时我就想,子类不是会自动调用父类的无参构造函数,那么为什么还要显式地调用父类的无参构造函数呢。难道加上保险点,反正我暂时还没想到这样做到底有什么样的好处,或许以后会发现点什么。朋友们,你们怎么看?
最后,再补充一句:若类没有定义构造函数,系统会自动隐式生成一个不带参数的构造函数。
为了说明这一点,我们删除MeClass类中定义的构造函数。运行程序后,查看其IL代码,发现系统确实为其生成了一个默认的无参构造函数,见下图“.ctor:void()”所示。
就这样了,8181。