摘要

我们都知道,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. 腾讯优测优分享 | Android性能测试工具化实现

    腾讯优测专业的移动云测试平台,自动化测试提供性能测试数据,云真机实时输出性能数据,让测试更简单! 1.Android性能测试介绍 提到Android性能测试,我们总免不了俗地要首先介绍下Android ...

  2. Can only set Cookies for the current domain

    # -*- coding: utf-8 -*- """ Created on Mon Dec 12 14:35:49 2016 @author: yaru "& ...

  3. zend studio 的使用

    1.将php项目导入到zend studio 中的方式为:http://my.oschina.net/maomi/blog/86077: 2.zend studio中将php项目导出的方式为:如果你会 ...

  4. coderforces #387 Servers(模拟)

    Servers time limit per test 2 seconds memory limit per test 256 megabytes input standard input outpu ...

  5. Android 的 DatePicker、TimePicker或NumberPicker

    布局文件加上这个就可以,去除日期选择器.时间选择器或数值选择器的可编辑状态. android:descendantFocusability="blocksDescendants" ...

  6. s2 devMode cmdshell

    s2 devMode cmdshell   仅支持批量验证,命令执行 链接:http://pan.baidu.com/s/1sl7tgRV 密码:wud8 也可以通过outscan一键获取,之后导入t ...

  7. PetaPoco ORM 增加返回DataTable的方法

    public DataTable ExecuteDataTable(Sql sql) { return ExecuteDataTable(sql.SQL, sql.Arguments); } publ ...

  8. CC2540中的电压检测

    /** * Battery level conversion from ADC to a percentage: * * The maximum ADC value for the battery v ...

  9. javascript中call函数与apply

    javascript中的call方法使当前对象可以调用另一个对象的方法,即改变this的指向内容 var first_object = { num: 42 }; var second_object = ...

  10. 常用Web Service汇总(天气预报、时刻表等)

      现成的Web Service中有很多很好用的,比如天气预报,IP地址搜索,火车时刻表等等.本文汇总的一些常用Web Service,希望对大家有所帮助. AD: ================= ...