C#构造函数在继承时必须要求与父类型构造函数入参相同怎么办?
摘要
我们都知道,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#构造函数在继承时必须要求与父类型构造函数入参相同怎么办?的更多相关文章
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
一.本文目的与说明 1. 本文目的:理清在各种继承时,构造函数.复制构造函数.赋值操作符.析构函数的执行顺序和执行内容. 2. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...
- C++类中的一些细节(重载、重写、覆盖、隐藏,构造函数、析构函数、拷贝构造函数、赋值函数在继承时的一些问题)
1 函数的重载.重写(重定义).函数覆盖及隐藏 其实函数重载与函数重写.函数覆盖和函数隐藏不是一个层面上的概念.前者是同一个类内,或者同一个函数作用域内,同名不同参数列表的函数之间的关系.而后三者是基 ...
- JAVA继承时构造函数的问题
今天看到java继承部分时,关于构造函数是否继承以及如何使用时遇到了点问题,后来查找相关资料解决了. 下面是我个人的总结: 先创建一个父类,里面有两个构造函数: public class Jisuan ...
- 【C++】继承时构造函数和析构函数
1. 顺序 先调用基类的构造函数,再调用派生类构造函数.析构顺序相反. 2. 构造函数 派生类 不用初始化列表调用基类构造函数->调用基类的默认构造函数 派生类 使用初始化列表调用基类带参构造函 ...
- scala中的面向对象定义类,构造函数,继承
我们知道scala中一切皆为对象,函数也是对象,数字也是对象,它是一个比java还要面向对象的语言. 定义scala的简单类 class Point (val x:Int, val y:Int) 上面 ...
- javascript面向对象(三):非构造函数的继承
本文来自阮一峰 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使用构造函数实现"继承" ...
- scala入门教程:scala中的面向对象定义类,构造函数,继承
我们知道scala中一切皆为对象,函数也是对象,数字也是对象,它是一个比java还要面向对象的语言. 定义scala的简单类 class Point (val x:Int, val y:Int) 上面 ...
- Javascript面向对象编程(三) --- 非构造函数的继承
一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese = { nation:'中国' }; 还有一个对象,叫做&qu ...
- Java构造函数的继承问题
◎构造函数的继承 1.子类只继承父类的默认(缺省)构造函数,即无形参构造函数.如果父类没有默认构造函数,那子类不能从父类继承到任何构造函数. 3.在创建对象时,先调用父类默认构造函数对对象进行初始化, ...
随机推荐
- cocos3.12预编译android报错RuntimeJsImpl.cpp
从coco官网下载了cocos2d-x-3.12.zip,在gen-libs生成prebuilt时,mac ,ios 平台都正常,android报错: jni/../../Classes/ide-su ...
- Gensim LDA主题模型实验
本文利用gensim进行LDA主题模型实验,第一部分是基于前文的wiki语料,第二部分是基于Sogou新闻语料. 1. 基于wiki语料的LDA实验 上一文得到了wiki纯文本已分词语料 wiki.z ...
- 合理利用gradle的占位符功能
1.gradle中可以声明字符串或者其他变量,然后再buildType中使用buildConfigField 来往BuildConfig文件中插入一个字符类型的常量,如下 先声明 def umengD ...
- 与考试相关的JS方法
var IsChange = 0;var ensure = 0;var timeCounter = (function () {//考试剩余时间 倒计时 var int; //var total = ...
- mysql 导入导出方法。
1.导出 mysqldump -u username - p databasename >名.sql enter passward: 2.导入:mysql -uroot -proot sour ...
- VS大视野
vs的本质:他是微软公司的员工一起开发的一个项目: 既然是项目:那么就是用编程语言编出来的! 用的是C# C#有他的特点:继承,封装,多态!等 我们在使用vs的时候,为什么可以使用很多的里面已经存在的 ...
- 【转载】Ansys中的阻尼
原文地址:http://www.cnblogs.com/ylhome/archive/2009/08/26/1554195.html ANSYS动力学分析中提供了各种的阻尼形式,这些阻尼在分析中是如何 ...
- Linux 下如何安装软件
一.解析Linux应用软件安装包 通常Linux应用软件的安装包有三种: 1) tar包,如software-1.2.3-1.tar.gz.它是使用UNIX系统的打包工具tar打包的. 2) rpm包 ...
- 全面解析sizeof(下) 分类: C/C++ StudyNotes 2015-06-15 10:45 263人阅读 评论(0) 收藏
以下代码使用平台是Windows7 64bits+VS2012. sizeof作用于基本数据类型,在特定的平台和特定的编译中,结果是确定的,如果使用sizeof计算构造类型:结构体.联合体和类的大小时 ...
- visual studio 的Error List 显示乱码
复制到右键菜单如下: Severity Code Description Project File LineError 閿欒: 绋嬪簭鍖卌om.baidu.lbsapi.auth涓嶅瓨鍦? com. ...