Inside C# 2nd Edition 边看边记 (2)

第四章杂记

1.ref、out、reference type、value type 好搞呀

都和函数调用的参数有关,
首先是value type,如果没有被任何修饰附修饰,那么就是值传啦,
如果被ref修饰的参数好像c++里面的指针,被out修饰效果也是差不多
但值得注意的问题是,如果函数的某个参数被ref修饰,则调用此函数前,
这个参数必须是赋值过的,如果是out修饰,则没有这个限制,但是out修饰的
参数在函数体内部必须被赋值。

接下来是reference type,在没有修饰附的情况下,reference type的表现和
加了ref的value type的表现相同,谁让人家生来就是reference呢。
下面看加了out的情况,以下几个函数,只有一个可以编译通过
class SomeClass
{
    // This won't compile
    public AnotherClass ChangeObject(out AnotherClass ref1)
    {
        ref1.ID = ref1.ID*2;
        return ref1;
    }
    // This won't compile
    public AnotherClass ChangeObject(out AnotherClass ref1)
    {
        ref1.ID = 4;
        return ref1;
    }
    // This won't compile
    public AnotherClass ChangeObject(out AnotherClass ref1)
    {
        int x = ref1.ID;
        ref1 = new AnotherClass();
        ref1.ID = x * 2;
        return ref1;
    }

    // This WILL compile
    public AnotherClass ChangeObject(out AnotherClass ref1)
    {
        ref1 = new AnotherClass();
        ref1.ID = 99;
        return ref1;
    }
}
原因就是out要求对此参数在函数体内部赋值,第一个函数没有赋值,编译不通过
第二个函数,同第一个;第三个函数,虽然new了一下,但是new的地方不对了,如果
先new再赋值就没有问题了,就像最后一个。

加个out已经如此郁闷了,看看加上ref效果如何吧
先看个函数
class AnotherClass
{
    public int ID;
}
class SomeClass
{
//      public AnotherClass ChangeObject(AnotherClass ref1)
    public AnotherClass ChangeObject(ref AnotherClass ref1)
    {
        ref1.ID = ref1.ID*2;
        return ref1;
    }
}

此处加了个ref,和不加的效果相同。最终都会改变调用函数中的ID的值
再看看下面的这个
class AnotherClass
{
    public int ID;
}
class SomeClass
{   
    public AnotherClass ChangeObject(ref AnotherClass ref1)
    {
        ref1.ID = ref1.ID*2;
        return ref1;
    }
    public void SubtleChange(
        ref AnotherClass ref1, AnotherClass ref2)
    {
        ref1 = new AnotherClass();
        ref1.ID = 999;

        ref2 = new AnotherClass();
        ref2.ID = 999;
    }
}

第一个ref1被ref修饰,因此当ref1被重新new的时候,调用函数中的原始值也
被重新分配了,但是ref2由于没有被任何修饰,所以就是一个值传而已,ref2
在函数体内被重新分配,而调用函数的原始值没有变化,就像传进来一个指针,
然后这个指针被重新指向新的地方,而调用函数中原始指针还是指着老地方,
而且函数内部没有对原始指针指向的数据做任何更改,所以下面的主函数调用的
结果就是:
class ValRefTest
{
    static void Main(string[] args)
    {
        SomeClass sc = new SomeClass();
        AnotherClass ref1 = new AnotherClass();
        ref1.ID = 3;
        AnotherClass ref2 = sc.ChangeObject(ref ref1);
        Console.WriteLine("ref1.ID = {0}, ref2.ID = {1}",
            ref1.ID, ref2.ID);

        sc.SubtleChange(ref ref1, ref2);
        Console.WriteLine("ref1.ID = {0}, ref2.ID = {1}",
            ref1.ID, ref2.ID);
    }
}
输出结果喂
ref1.ID = 6, ref2.ID = 6
ref1.ID = 999, ref2.ID = 6

2.函数重载overloading

值得说明有一条,关于ref和out的。对于两个函数,编译器认为不加ref或out的函数可以和加ref或out的函数
构成重载,但是两个同时加了ref或out的函数不可以

函数一:
protected void WriteEntry(string entry)
{
    Console.WriteLine(entry);
}

函数二:
public void WriteEntry(ref string entry)
{
    Console.WriteLine(entry);
}

函数三:
public void WriteEntry(out string entry)
{
    entry = "Foo";
    Console.WriteLine(entry);
}

函数一和二或者三构成重载,但是二、三不能同时存在

3.overriding和overloading的区别

一个一直以来不是很清楚的问题,今天才想起来搜索一下,原来有如此精辟的解释,相见恨晚呀

方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性
的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称
和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,
父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的
参数类型,则称为方法的重载(Overloading)。

4.virtual、override、new几个关键字

举个小例子吧
class A
{  
 public void f( int i )
 {
  m_i = i*i;
 }
 protected int m_i;
}


class B :  A
{  
 public new void f( int i )
 {
  m_i = i;
 }
}

当继承类中需要重新改写基类中的一个函数的时候,需要使用new关键字,否则编译错误。
此时B b=new B();b.f(100);调用的是B::f(),
A a =new B();a.f();调用的是A::f(),
这里不存在任何多态的概念,只是一个函数的覆盖过程,声明为谁,就调用谁的函数,

但加入了virtual后,就出现了多态的概念

class A
{  
 public virtual void f( int i )
 {
  m_i = i*i;
 }
 protected int m_i;
}


class B :  A
{  
 public override void f( int i )
 {
  m_i = i;
 }
}

注意f前加入了virtual关键字。基本上与c++中的虚函数概念相同,只是在继承类中需要加入override这个关键字
此时B b=new B();b.f(100);调用的是B::f(),这个毫无疑问,不调用它调用谁呢
A a =new B();a.f();调用的也是B::f(),这个就是多态的问题了,与虚函数表有关的一大堆东西需要提起了

参看c++里面虚函数的解释

http://blog.csdn.net/zdliang/archive/2005/04/15/348772.aspx


5.静态函数

注意类中静态函数能构访问的范围就可以了,静态函数只能访问类中的静态变量,成员函数可以访问静态变量和成员变量
但this不能访问静态变量。

静态构造函数不能有参数,不能被public等修饰附修饰,静态构造函数在构造函数前被调用。看下面的代码

class SomeClass
{
    public static int x;

    static SomeClass()
    {
        x = 1;
        Console.WriteLine("SomeClass initialized");
    }

    public SomeClass()
    {
        Console.WriteLine("Non-static ctor");
    }

    public static void Foo()
    {
        Console.WriteLine("Foo");
    }
}

class Test
{
    static void Main(string[] args)
    {
        // 下面三行代码都将导致静态构造函数的调用
        SomeClass sc = new SomeClass();
        SomeClass.Foo();
        Console.WriteLine(SomeClass.x);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值