C#上机笔记(第七次上机)

各位同学:
    大家好!
    这次上机的主要任务是研究泛型、类的派生与继承、多态等内容。
1. 研究cs095,完成如下工作:
    a.了解:如果两个重载的函数只有参数的类型不同,而其他的都相同,这样的两个函数就应该用泛型函数统一起来。
    b.了解:任何一种数据类型E的数组E[],都一定实现了IEnumerable 接口。只有实现了这个接口的容器,才能使用foreach语句进行遍历。
    c.了解:在C#中,能够用throw抛出的对象一定是Exception(或其派生类)的对象。用户自定义异常类通常继承自ApplicationException类。其中,成员属性StackTrace描述了异常对象从抛出到被捕获之前的所有函数调用及其位置。

using System;

class FullStackException : ApplicationException
{
   // parameterless constructor
   public FullStackException() : base( "Stack is full" )
   {
      // empty constructor
   } // end FullStackException constructor

   // one-parameter constructor
   public FullStackException( string exception ) : base( exception )
   {
      // empty constructor
   } // end FullStackException constructor
} // end class FullStackException


    d.泛型的类型参数通常是需要约束的。可以同时指定多个约束,用逗号格开,其中new()约束必须放在最后。请自己编写一个带多个约束的泛型方法。
约束类型:

约束说明
where T:struct使用结构约束,类型T必须是值类型
where T:class类约束指定,类型T必须是引用类型
where T:IFoo指定类型T必须执行接口IFoo
where T:Foo指定类型T必须派生于基类Foo
where T:new()这是一个构造函数约束,指定类型T必须有一个默认构造函数
where T:U这个约束也可以指定,类型T1派生于泛型类型T2。该约束也称为裸类型约束
example:
class Stack< E > where E:class,new()


2. 研究samename.cs,了解如何在派生类中访问被隐藏的基类成员(使用关键字base),了解如果有意隐藏基类成员,最好使用关键字new。同时,思考如下问题:为什么最好完全避免隐藏的发生。

using System;
using System.Collections.Generic;
using System.Text;

namespace samename
{
    class A
    {
        protected int x;
        public A(int i)
        {
            x = i;
        }
        public void show()
        {
            Console.WriteLine(x);
        }
    }
    class B : A
    {
        double x;
        public B(double d)
            : base(1)
        {
            x = d;
        }
        public void show()
        {
            Console.WriteLine(x);
        }
        public void show1()
        {
            Console.WriteLine(base.x);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            B b = new B(5.8);
            b.show();
            b.show1();
            Console.ReadLine();
        }
    }
}

Warning    1    'samename.B.show()' hides inherited member 'samename.A.show()'. Use the new keyword if hiding was intended.    C:/Documents and Settings/Administrator/My Documents/Visual Studio 2008/Projects/ConsoleApplication1/ConsoleApplication1/Program.cs    27    21    ConsoleApplication1
使用new关键字可以消除警告,但效果不变:

public new void show();

声明的可访问性
含义

public

访问不受限制。

protected

访问仅限于包含类或从包含类派生的类型。

internal

访问仅限于当前程序集。

protected internal

访问仅限于从包含类派生的当前程序集或类型。

private

访问仅限于包含类型。


3. 研究Convert.cs,思考如下问题:
    a.我们说把A类转换成B类,是通过A类对象创建一个新的B类对象吗?如果不是,那么转换的具体含义又是什么呢?
    b.既然向下转换(基类转换成派生类)是不安全的,那么为什么不在编译的时候就禁止?

using System;
using System.Collections.Generic;
using System.Text;

namespace cs043
{
    class A { }
    class B : A { };
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
//            A a = new B();
            B b = (B)a;
            Console.ReadLine();
        }
    }
}
使用A a = new A(); 则运行时报错;

未处理的异常:  System.InvalidCastException: 无法将类型为“cs043.A”的对象强制转
换为类型“cs043.B”。
   在 cs043.Program.Main(String[] args) 位置 C:/Documents and Settings/Administr
ator/My Documents/Visual Studio 2008/Projects/ConsoleApplication1/ConsoleApplica
tion1/Program.cs:行号 15
5.5 C#高级编程:用户定义的数据类型转换(1)
5.5 C#高级编程:用户定义的数据类型转换(2)
在进行数据类型转换时,会检查被引用的对象。因为基类引用实际上可以引用一个派生类实例,所以这个对象可能是要转换的派生类的一个实例。如果是这样,转换就会成功,派生的引用被设置为引用这个对象。但如果该对象不是派生类(或者派生于这个类的其他类)的一个实例,转换就会失败,抛出一个异常。

使用A a = new B(); 正确


4. 研究KnowType.cs,了解如下事实:
    a.通过is操作可以判断一个引用的动态数据类型,这种判断不是排他性的。派生类对象可以被当作任何一个基类对象看待。
    b.obj.GetType()返回一个System.Type类型的对象。通过MSDN查看一下该类对象有哪些成员函数。

using System;
using System.Collections.Generic;
using System.Text;

namespace knowtype
{
    class Base { }
    class Derived : Base { }
    class Program
    {
        static int TypeID(object ob)
        {
            
            if (ob is Base) return 1;if (ob is Derived) return 2;       //注意:把这句话移到第二行,运行结果就会有问题,试试看!
            return 0;
        }
        static void Distinguish(object obj)
        {
            switch (TypeID(obj))
            {
                case 1: Console.WriteLine("Base"); break;
                case 2: Console.WriteLine("Derived"); break;
                default: Console.WriteLine(obj.GetType()); break;
            }
        }
        static void Main(string[] args)
        {
            Base a = new Base();
            Derived b = new Derived();
            Distinguish(a);
            Distinguish(b);
            Distinguish(1);
            Console.ReadLine();
        }
    }
}


5. 研究cs102,完成如下工作:
    a.了解:可用typeof操作符直接作用于某种数据类型,从而返回相应的Type对象。
    b.定义byte a,b;利用(a+b).getType()查看该表达式的数据类型。
(a+b)类型是System.Int32

6. 研究virtual.cs,完成如下工作:
    a.了解:抽象类中可以不包含任何一个抽象方法。但包含抽象方法的类一定是抽象类。抽象方法一定是虚方法。
    b.了解:虚方法在派生类中如果不被显式改写,那么将继承基类中的版本。
    c.了解:如果用new关键字在派生类中定义了一个与基类的虚方法同名的方法,实际上是阻止了该虚方法的进一步改写。

using System;
using System.Collections.Generic;
using System.Text;

namespace virtualfunc
{
    abstract class Concrete {
        public void show() { }
    }
    abstract class A {
        public abstract void show();
    }
    class B : A {
        public override void show() {
            Console.WriteLine("B");
        }
    }
    class C : B {
        override public void show()   //将override关键字改为new再试一试
        {
            Console.WriteLine("C");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
//            Concrete obj = new Concrete();       //只要是用abstract说明的类一定是抽象类,不能被实例化
            A a = new B();
            B b=(B)a;
            a.show();
            b.show();
            a = new C();
            a.show();
            ((C)a).show();
            Console.ReadLine();
        }
    }
}


7. 研究AbstractShapes。完成如下的工作:
    a.了解:属性(Property)表面上看起来像字段,但实际上是类的方法成员,所以可以声明抽象属性,并在派生类中改写。
    b.了解:基类中的虚方法,在派生类的成员函数中可以被“实调用”,即用base.f()的形式调用。函数的入口地址是在编译时决定的。
    c.了解:用一个基类的数组,数组的每个分量指向不同的派生类对象,然后统一调用数组每个分量的虚函数,是利用多态机制进行程序设计的典型案例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值