摘要

我们都知道,C#中,在类型继承时,由于构造子类必须先构造其父类型的内容,因此,必须子类型的构造函数中调用父类型的构造函数(无参数的不需要显式声明)。

但是往往我们会出现,子类型本身的构造函数大于或小于父类型构造函数的情况,那我们应该怎么办呢?


简单情景:父类型需要两个参数,而子类型只需一个参数

比如我们有一个专门用来计算两个数相乘的类型:

class Multi
{
public int Result { get; private set; } public Multi(int i,int j)
{
this.Result = i * j;
}
}

然后,乘法中有一个特殊的情况就是平方,如果我们再建立一个类型用于直接计算平方的话,那构造函数只需要一个值就行了。

但是由于我们继承的父类型的构造函数有两个参数,所有我们要使用一些特殊的语法来标明,子类如何调用父类型的构造函数:

class Squ : Multi
{
public Squ(int i)
: base(i, i) //通过这行代码,表示在new Squ(i)时,执行new Multi(i,i);
{ }
}

复杂情景:子类型构造时的参数,不能直接用于父类型的构建,需要经过非常复杂的过程才能得到父类型的构建参数

这是一种极少数情况下会遇到情况。

但是遇到以后,如果经验不足,大家也会不知道如何下手处理。

我们继续使用上面的Multi作为父类型,实现一个子类,用于“计算一元二次方程中的一正整数解”的子类出来。

——呃,这怎么可能。。。。。

想必大家的第一反应是这样的。

那我们就来仔细分析一下,一元二次方程的求根公式是 ( -b ± √(b * b - 4 * a * c) / (2 * a)

除一个数,其实就是乘以它的相反数嘛。

于是这就变成了构建一个Multi对象,第一个参数是-b ± √(b * b - 4 * a * c),第二个参数是 1 / (2 * a)嘛

但是我们的命题是“正整数解”也就是说,我们还要加入一些判断逻辑在里面,在仅仅的一行base(xxx,yyy)中间,我们有办法实现这么多代码吗?

答案很简单:当然没办法在base中写入这么多代码!最糟糕的是,我们还只能在base里面写这些复杂的逻辑。

————那。。。。该如何时好呢?

答案就是“静态方法”,静态函数在类型第一次被访问时就已经初始化好了,那么在实例化时,更不用,早就存在内存中了。

通过静态方法,以及ref或out关键字,我们可以以静态函数作为媒介,创建出一个完全符合要求的base语句来。

class MyFunc : Multi
{
private static int CtorExt(int a, int b, int c, ref int j)
{
var d = b * b - * a * c; //求delta,与0的比较不在此示例中演示
var sd = Math.Sqrt(d); //求平方根
var i1 = -b + sd; //计算两个根的分子
var i2 = -b - sd;
j = * a;
//判断与j的符号性,当符号相同时(正数)返回
//注明:返回整数形式仅示例作用
if (i1 > && j > ) return (int)i1;
if (i1 < && j < ) return (int)i1;
if (i2 > && j > ) return (int)i2;
if (i2 < && j < ) return (int)i2;
throw new ApplicationException("无正数解");
} public MyFunc(int a, int b, int c, int j)
: base(CtorExt(a, b, c, ref j), j)
{ }
}

通过上面这种复杂的方式,我们在子类的构造函数中,执行了CtroExt这个静态方法,这个方法返回了用于构建父类型的第一个参数i,还通过ref关键字,得到了用于构建父类型的第二个参数j,于是base语句得到了完美的使用。

但是美中不足的是,子类的构建函数多了一个j作为入参,但是外部调用的时候,这个j毫无意义(因为值是最终会被CtorExt所替换,为了保证一个好的调用环境,我们应该将这个构造函数设为私有,再为新增一个符合要求的构造函数

class MyFunc : Multi
{
private static int CtorExt(int a, int b, int c, ref int j)
{
var d = b * b - * a * c; //求delta,与0的比较不在此示例中演示
var sd = Math.Sqrt(d); //求平方根
var i1 = -b + sd; //计算两个根的分子
var i2 = -b - sd;
j = * a;
//判断与j的符号性,当符号相同时(正数)返回
//注明:返回整数形式仅示例作用
if (i1 > && j > ) return (int)i1;
if (i1 < && j < ) return (int)i1;
if (i2 > && j > ) return (int)i2;
if (i2 < && j < ) return (int)i2;
throw new ApplicationException("无正数解");
} private MyFunc(int a, int b, int c, int j)
: base(CtorExt(a, b, c, ref j), j)
{ }
public MyFunc(int a, int b, int c)
: this(a, b, c, ) //因为j最终会被替代,因此这里随便写什么值都行
{ }
}

总结:

1、这种解决方案也是“封装”思想的体现,将一个复杂的方法封装,并直接调用,可以得到我们想要的结构,而不关心实现过程。

2、静态函数是可以在造构函数刚发生时使用的,因为它“早已准备好了”

3、ref关键字在这里非常重要

4、这是一种阅读性不是非常好的编方式,不到万不得已时,尽可能不要使用。

原文地址 http://www.zizhusoft.com/note/show.aspx?id=a8240ee2-eeeb-4cb3-bc7e-00aec29476f2

C#构造函数在继承时必须要求与父类型构造函数入参相同怎么办?的更多相关文章

  1. C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容

    一.本文目的与说明 1. 本文目的:理清在各种继承时,构造函数.复制构造函数.赋值操作符.析构函数的执行顺序和执行内容. 2. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...

  2. C++类中的一些细节(重载、重写、覆盖、隐藏,构造函数、析构函数、拷贝构造函数、赋值函数在继承时的一些问题)

    1 函数的重载.重写(重定义).函数覆盖及隐藏 其实函数重载与函数重写.函数覆盖和函数隐藏不是一个层面上的概念.前者是同一个类内,或者同一个函数作用域内,同名不同参数列表的函数之间的关系.而后三者是基 ...

  3. JAVA继承时构造函数的问题

    今天看到java继承部分时,关于构造函数是否继承以及如何使用时遇到了点问题,后来查找相关资料解决了. 下面是我个人的总结: 先创建一个父类,里面有两个构造函数: public class Jisuan ...

  4. 【C++】继承时构造函数和析构函数

    1. 顺序 先调用基类的构造函数,再调用派生类构造函数.析构顺序相反. 2. 构造函数 派生类 不用初始化列表调用基类构造函数->调用基类的默认构造函数 派生类 使用初始化列表调用基类带参构造函 ...

  5. scala中的面向对象定义类,构造函数,继承

    我们知道scala中一切皆为对象,函数也是对象,数字也是对象,它是一个比java还要面向对象的语言. 定义scala的简单类 class Point (val x:Int, val y:Int) 上面 ...

  6. javascript面向对象(三):非构造函数的继承

    本文来自阮一峰 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使用构造函数实现"继承" ...

  7. scala入门教程:scala中的面向对象定义类,构造函数,继承

    我们知道scala中一切皆为对象,函数也是对象,数字也是对象,它是一个比java还要面向对象的语言. 定义scala的简单类 class Point (val x:Int, val y:Int) 上面 ...

  8. Javascript面向对象编程(三) --- 非构造函数的继承

    一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese = { nation:'中国' }; 还有一个对象,叫做&qu ...

  9. Java构造函数的继承问题

    ◎构造函数的继承 1.子类只继承父类的默认(缺省)构造函数,即无形参构造函数.如果父类没有默认构造函数,那子类不能从父类继承到任何构造函数. 3.在创建对象时,先调用父类默认构造函数对对象进行初始化, ...

随机推荐

  1. Linux系统上通知网关更新arp

    经常会有在线更换Linux服务器IP的操作,该操作带来的一个问题是: 我们已经执行了修改IP的操作,但由于网络上(网关)的ARP缓存暂未更新,导致在某一段时间内,该服务器会有网络不通的情况存在. 因此 ...

  2. Tomcat报错:Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]

    Failed to start component [StandardEngine[Catalina].StandardHost[localhost]] 解决办法: 1,检测你的web.xml.去掉所 ...

  3. 【转载】ANSYS 动力分析 (9) - 瞬态动力分析 (1)

    原文地址:http://htbbzzg.blog.163.com/blog/static/69725206201081663611208/ 第四章   瞬态动力分析 第一节:瞬态动力分析的定义和目的  ...

  4. 嵌入式系统添加无线wifi模块

    开发环境:fl2440开发板,linux3.0内核,交叉编译器路径/opt/buildroot-2011.11/arm920t/usr/bin/arm-linux-,无线网卡RT3070 平时开发板联 ...

  5. 【转载】Python 描述符简介

    来源:Alex Starostin 链接:www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 关于Python@修饰符的文章可 ...

  6. SQL Server 连接字符串备忘

    今天把服务器上的远程访问关了,把连接字符串中的IP地址改成了.,然后就一直连不上.弄了半天,原来是本地连接时非默认实例,不能带端口号. 1.原来的连接服务器地址是:192.168.0.1SQL2005 ...

  7. RPC与hadoop

    rlgdj的这样的话,真正的实现类在Server端,客户端调用方法的时候,只能得到得到从Server端的返回值.看来接口中的抽象方法必须要有返回值啊.ps.右下角的Client端的main()中rpc ...

  8. mysql强更改root密码

    在丢失root密码的时候,可以这样 要先停掉 mysql服务 mysqld_safe --skip-grant-tables& mysql -u root mysql mysql> UP ...

  9. == 与 equals 的区别

    今天跟开发修复一个bug,现在列出来这个绕口的比较 场景一: Long a = 1: Long b = 1: boolean result = (a == b); //此时result的值为false ...

  10. Head First 设计模式之观察者模式(Observer Pattern)

    前言: 这一节开始学习观察者模式,开始讲之前会先像第一节那样通过一个应用场景来引入该模式.具体场景为:气象站提供了一个WeatherData对象,该对象可以追踪获取天气的温度.气压.湿度信息,Weat ...