第四章杂记
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.youkuaiyun.com/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);
}
}