C#类继承与重载的问题,Mat继承于Matrix,但提示无法将类型隐式转换为 存在一个显式转换 是不是缺少强制转

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#类继承与重载的问题,Mat继承于Matrix,但提示无法将类型隐式转换为 存在一个显式转换 是不是缺少强制转相关的知识,希望对你有一定的参考价值。

已有一个Matrix类,想对其进行扩充,于是定义了一个Mat类继承于Matrix ,如下
//重载Matrix
public class Mat : Matrix

//构造函数,由一维数组构造矩阵
public Mat(int row, int col, double[] data) : base(row, col)
for (int i = 0; i < row; i++)

for (int j = 0; j < col; j++)

this[i, j] = data[i * row + j];




……

使用时在这里提示错误:Mat a=b.Transpose(); //Transpose()是Matrix中的一个方法
我的工程名称是MathNet.Numerics,错误信息为:
错误 1 无法将类型“DotNumerics.LinearAlgebra.Matrix”隐式转换为“MathNet.Numerics.Mat”。存在一个显式转换(是否缺少强制转换?) D:\My Documents\Visual Studio 2008\Projects\MathNet.Numerics\MathNet.Numerics\Program.cs 140 18 MathNet.Numerics

无法将基类对象直接赋值给子类对象
就像“动物”和“狗”
可以把狗赋值给动物(也就是说狗是动物)
但是不可以把动物赋值给狗(不能说动物就是狗)
这样说你能理解吧?
所以你这个地方需要一个显示的强制转换,前提是你确认这个动物就是狗的情况下,否则会出现强制转换异常。
改为:Mat a = (Mat)b.Transpose();追问

你说的我理解了,我的目的是扩充父类的方法,然后父类原有的方法在子类中可以用
但这样也不行,再说也不方便啊,我用Mat a = (Mat)b.Transpose(); 打印时抛出错误:
未处理的异常: System.InvalidCastException: 无法将类型为“DotNumerics.LinearAlge
bra.Matrix”的对象强制转换为类型“MathNet.Numerics.Mat”。 在 MathNet.Numerics.Program.Main(String[] args) 位置……
怎么办啊?

追答

你确认两件事情:
1:Mat类是否真的继承Matrix类(有没有其他重名的类?)
2:有没有其他类继承自Matrix,而你的Transpose()这个方法返回的实际上不是Mat类的对象

比如猫和狗都继承动物
你这个方法返回一个猫,你却非要把猫强制转换成狗,当然会出异常。
只要保证上面2件事情,绝对不会有错误。

追问

要不我把工程文件发给你看看吧,很简单的,没写几行代码,就想做一个简单的扩充,请问邮箱多少?谢谢啦

追答

。。
zhaozhekang110@163.com
发来吧

追问

已发送,注意查收,谢谢~

追答

我Hi你了,怎么没反应?

参考技术A 是缺少了强制转换。在相应 的地方加上强制转换估计就OK了

C#继承重载与接口的引入

这篇是对上篇的补充,和之前计划的有点小差异,多层次继承需要再往后靠靠了,还是先看代码

namespace ConsoleApp1


    public interface It
    
        void PI();
    

    public class A:It
    
        private int _type = 0;
        public int Type = 0;

        public A(int type)
        
            Type = _type = type;
        

        public virtual void P()
        
            Console.WriteLine("这是A的PP!");
        

        public virtual void PI()
        
            Console.WriteLine("这是A的PI!");
        

        public void Dispatch()
        
            switch (_type)
            
                case 1:
                    (this as B).P();
                    break;
                case 2:
                    (this as C).P();
                    break;
            
        
    

    public class B : A
    
        public B(int type) : base(type)  

        public override void P()
        
            Console.WriteLine("这是B的PP!");
        

        public override void PI()
        
            Console.WriteLine("这是B的PI!");
        
    

    public class C : A
    
        public C(int type) : base(type)  

        public override void P()
        
            Console.WriteLine("这是C的PP!");
        

        public override void PI()
        
            Console.WriteLine("这是C的PI!");
        
    


namespace ConsoleApp1

    class Program
    
        static void Main(string[] args)
        
            _dictClass.Add(0, new A(0));
            _dictClass.Add(1, new B(1));
            _dictClass.Add(2, new C(2));

            _dictInterface.Add(0, new A(0));
            _dictInterface.Add(1, new B(1));
            _dictInterface.Add(2, new C(2));

            _dictClass[0].P();
            Console.WriteLine(_dictClass[0].Type);
            _dictClass[1].P();
            Console.WriteLine(_dictClass[1].Type);
            _dictClass[2].P();
            Console.WriteLine(_dictClass[2].Type);

            Console.WriteLine();
            Console.WriteLine("ding------------------------------ding");
            Console.WriteLine();

            _dictClass[1].Dispatch();
            _dictClass[2].Dispatch();

            Console.WriteLine();
            Console.WriteLine("ding------------------------------ding");
            Console.WriteLine();

            _dictInterface[0].PI();
            _dictInterface[1].PI();
            _dictInterface[2].PI();
        

        private static Dictionary<int, It> _dictInterface = new Dictionary<int, It>();
        private static Dictionary<int, A>  _dictClass = new Dictionary<int, A>();
    

再看看结果:

技术图片

先来解释下,这一次测试对代码进行了稍微的改进,引入了两个变量,同时加了一个Dispatch

A b = new B(1);

这个变量的引入是为了更加直观的描述这一行代码,首先构造B实例,B继承A因此在B构造之前先对A进行了构造,

并且在父类构造的同时,赋值变量Type、_type 都为1,而Type是public的可以被子类继承

因此b.Type = 1,这样相比应该都明白了吧,而c是和它一样的,就不再说了。

可能你已经发现了,引入的_type与Dispatch关联到了一块了,

没错,我用它来进行指令的分派,也就是做动态管理时会经常用到的,这样一来,子类继承自父类时可以不用重载父类的方法就能实现一些额外的功能,而这个父类就变成了一个转发器。

实际上这种写法并不好,父类是不应该参与子类的具体行为的,所以我打算再修改一下。

namespace ConsoleApp1


    public interface It
    
        void PI();
    

    public class A:It
    
        private int _type = 0;
        public int Type = 0;
        public A a;

        public A(int type)
        
            Type = _type = type;
        

        public virtual void P()
        
            Console.WriteLine("这是A的PP!");
        

        public virtual void PI()
        
            Console.WriteLine("这是A的PI!");
        

        public void Dispatch()
        
            Console.WriteLine("这里是指令分派的接口哦!");
            a.P();
        
    

    public class B : A
    
        public B(int type) : base(type) 
            a = this;
        

        public override void P()
        
            Console.WriteLine("这是B的PP!");
        

        public override void PI()
        
            Console.WriteLine("这是B的PI!");
        
    

    public class C : A
    
        public C(int type) : base(type) 
            a = this;
        

        public override void P()
        
            Console.WriteLine("这是C的PP!");
        

        public override void PI()
        
            Console.WriteLine("这是C的PI!");
        
    

你应该看出来了,这里去掉了_type与switch,改用实例本身来进行指令分派

来看看结果

技术图片

结果和之前是一样的,这样一来,就避免了父类对子类的干预,而仅仅只是作为一个转发器。

看到这里,你应该会疑惑,这样写有什么意义呢?直接掉子类的重载方法不就行了吗,何必多此一举呢?

没错,这样做的确画蛇添足,但如果子类不进行重载的话,那么会怎么样子呢?

 

namespace ConsoleApp1


    public interface It
    
        void PI();
    

    public class A:It
    
        private int _type = 0;
        public int Type = 0;
        public A a;

        public A(int type)
        
            Type = _type = type;
        

        public void P()
        
            Console.WriteLine("这是A的PP!");
        

        public virtual void PI()
        
            Console.WriteLine("这是A的PI!");
        

        public void Dispatch()
        
            Console.WriteLine("这里是指令分派的接口哦!");
            a.P();
        
    

    public class B : A
    
        public B(int type) : base(type) 
            a = this;
        

        public new void P()
        
            Console.WriteLine("这是B的PP!");
        

        public override void PI()
        
            Console.WriteLine("这是B的PI!");
        

        public void PP()
        

        
    

    public class C : A
    
        public C(int type) : base(type) 
            a = this;
        

        public new void P()
        
            Console.WriteLine("这是C的PP!");
        

        public override void PI()
        
            Console.WriteLine("这是C的PI!");
        

        public void PP()
        
            Console.WriteLine("这是C的PP!");
        
    

 

看看结果

技术图片

无论是哪一种,似乎都没什么用了,这是因为,我在接收实例的时候统统转化为A声明的实例,这样一来,没有进行重载的话,这些实例即使拥有和父类相同的方法,也只能以父类为模板进行表现,要想实现子类的特性,必须将这个实例重新转化为它的构造类型,如(b as B).PP();

下面看张图

技术图片

这张图很很好的解释了刚才说的。

如此一来,如果想实现父类对子类的管理,那么子类被管理的方法必须要被重载才行,在笔者理解来,重载就像是一个关联起来的映射,如果这个映射存在,那么这个方法呈现的效果就是子类的效果,如果不存在,那就只显示父类结果,父类就像是一个小箱子,子类就像是一个大箱子包裹着父类这个小箱子,若果两者之间有映射,那么父类可以沿着这条线来操纵子类在大箱子里表演,否则只能在里面的小物体自导自演了。

这样的话,似乎这个负责管理的转发器也并不是很好用啊,或许你可以多写几个虚函数来对子类行为进行映射扩充,但这似乎并不符合面向对象编程的思想,而且行为上很相似抽象和接口,会造成很多的冗余。

那么问题来了,写这篇扩展的意义是什么呢?

两个方面,

一是想看看面向对象的编程,父与子的关系究竟如何。

二和编写框架有关,按照笔者的思路,框架的管理思想是由上到下,最上级是管理者和协调者,能够统一的处理一类事情,而下级则是具体的执行者,看上去很像父子的继承关系,实际上也确实是这样的。

大概是笔者比较转牛角尖,总是希望所有的对象都能通过一个管理者来协调,虽然最后通过组合模块的方式也实现了,但距离笔者想要的结果还是有点差距,因此才往这方面进行了一些研究,虽然结果并不一定是自己想要的,但重要的是思考问题的方式,以及过程中的收获。

那么在这里结束这篇没有结果的思路吧,下一篇开始多层次继承的研究。

 

以上是关于C#类继承与重载的问题,Mat继承于Matrix,但提示无法将类型隐式转换为 存在一个显式转换 是不是缺少强制转的主要内容,如果未能解决你的问题,请参考以下文章

C#继承重载与接口的引入

C#之封装继承多态初识

C++继承详解

C++继承详解

Java 继承与重写重载

使用继承的 C# 重载方法调用 [重复]