10.this 关键字的含义?
11.可以使用抽象函数重写基类中的虚函数吗?
12.密封类可以有虚函数吗?
13.如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后可以有几个属性访问器?如果基类中有 get 和 set 两个呢?
14.abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
15.接口可以包含哪些成员?
16.类和结构的区别?
17.接口的多继承会带来哪些问题?
18.抽象类和接口的区别?
10. this 关键字的含义?
答: this 是一个保留字,仅限于构造函数和方法成员中使用.
在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用.
this
保留字不能用于静态成员的实现里,因为这时对象或结构并未实例化
.
在
C#
系统中,
this
实际上是一个常量,所以不能使用
this++
这样的运算
.
this 保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example10
{
class Class1
{
private double c;
private string value;
public double C
{
get
{
return c;
}
}
public Class1(double c)
{
// 限定同名的隐藏成员
this.c = c;
}
public Class1(Class1 value)
{
// 用对象本身实例化自己没有意义
if (this != value)
{
c = value.C;
}
}
public override string ToString()
{
// 将对象本身做为参数
return string.Format("{0} Celsius = {1} Fahrenheit", c, UnitTransClass.C2F(this));
}
// 由于好奇,在这做了一个效率测试,想看看到底哪种方式访问成员变量更快,结论:区别不大。。。
public string Test1()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
this.value = i.ToString();
return string.Format("Have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
public string Test2()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
value = i.ToString();
return string.Format("Don't have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
}
class UnitTransClass
{
public static double C2F(Class1 value)
{
// 摄氏到华氏的转换公式
return 1.8 * value.C + 32;
}
}
class Program
{
static void Main(string[] args)
{
Class1 tmpObj = new Class1(37.5);
Console.WriteLine(tmpObj);
Console.WriteLine(tmpObj.Test1());
Console.WriteLine(tmpObj.Test2());
Console.ReadLine();
}
}
}
结果:
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don't have this.: 4406 MSEL
this 保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example10
{
class Class1
{
private double c;
private string value;
public double C
{
get
{
return c;
}
}
public Class1(double c)
{
// 限定同名的隐藏成员
this.c = c;
}
public Class1(Class1 value)
{
// 用对象本身实例化自己没有意义
if (this != value)
{
c = value.C;
}
}
public override string ToString()
{
// 将对象本身做为参数
return string.Format("{0} Celsius = {1} Fahrenheit", c, UnitTransClass.C2F(this));
}
// 由于好奇,在这做了一个效率测试,想看看到底哪种方式访问成员变量更快,结论:区别不大。。。
public string Test1()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
this.value = i.ToString();
return string.Format("Have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
public string Test2()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
value = i.ToString();
return string.Format("Don't have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
}
class UnitTransClass
{
public static double C2F(Class1 value)
{
// 摄氏到华氏的转换公式
return 1.8 * value.C + 32;
}
}
class Program
{
static void Main(string[] args)
{
Class1 tmpObj = new Class1(37.5);
Console.WriteLine(tmpObj);
Console.WriteLine(tmpObj.Test1());
Console.WriteLine(tmpObj.Test2());
Console.ReadLine();
}
}
}
结果:
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don't have this.: 4406 MSEL
10.this
关键字的含义?
答: this 是一个保留字,仅限于构造函数和方法成员中使用 .
在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用 .
答: this 是一个保留字,仅限于构造函数和方法成员中使用 .
在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用 .
this
保留字不能用于静态成员的实现里,因为这时对象或结构并未实例化
.
在
C#
系统中,
this
实际上是一个常量,所以不能使用
this++
这样的运算
.
this 保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example10
{
class Class1
{
private double c;
private string value;
public double C
{
get
{
return c;
}
}
public Class1(double c)
{
// 限定同名的隐藏成员
this.c = c;
}
public Class1(Class1 value)
{
// 用对象本身实例化自己没有意义
if (this != value)
{
c = value.C;
}
}
public override string ToString()
{
// 将对象本身做为参数
return string.Format("{0} Celsius = {1} Fahrenheit", c, UnitTransClass.C2F(this));
}
// 由于好奇,在这做了一个效率测试,想看看到底哪种方式访问成员变量更快,结论:区别不大。。。
public string Test1()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
this.value = i.ToString();
return string.Format("Have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
public string Test2()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
value = i.ToString();
return string.Format("Don't have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
}
class UnitTransClass
{
public static double C2F(Class1 value)
{
// 摄氏到华氏的转换公式
return 1.8 * value.C + 32;
}
}
class Program
{
static void Main(string[] args)
{
Class1 tmpObj = new Class1(37.5);
Console.WriteLine(tmpObj);
Console.WriteLine(tmpObj.Test1());
Console.WriteLine(tmpObj.Test2());
Console.ReadLine();
}
}
}
结果:
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don't have this.: 4406 MSEL
11. 可以使用抽象函数重写基类中的虚函数吗?
答:可以,但需使用 new 修饰符显式声明,表示隐藏了基类中该函数的实现
示例 :
class BaseClass
{
public virtual void F()
{
Console.WriteLine("BaseClass.F");
}
}
abstract class DeriveClass : BaseClass
{
public new abstract void F();
}
12. 密封类可以有虚函数吗?
答:可以,基类中的虚函数将隐式的转化为非虚函数,但密封类本身不能再增加新的虚函数
示例:
class BaseClass
{
public virtual void F()
{
Console.WriteLine("BaseClass.F");
}
}
sealed class DeriveClass : BaseClass
{
// 基类中的虚函数 F 被隐式的转化为非虚函数
// 密封类中不能再声明新的虚函数 G
//public virtual void G()
//{
// Console.WriteLine("DeriveClass.G");
//}
}
13. 如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后可以有几个属性访问器?如果基类中有 get 和 set 两个呢?
答:如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后也应只有一个。如果基类中有 get 和 set 两个属性访问器,那么继承类中可以只有一个也可以同时有两个属性访问器
14.abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
答: abstract 修饰符不可以和 static 、 virtual 和 override 修饰符一起使用
this 保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example10
{
class Class1
{
private double c;
private string value;
public double C
{
get
{
return c;
}
}
public Class1(double c)
{
// 限定同名的隐藏成员
this.c = c;
}
public Class1(Class1 value)
{
// 用对象本身实例化自己没有意义
if (this != value)
{
c = value.C;
}
}
public override string ToString()
{
// 将对象本身做为参数
return string.Format("{0} Celsius = {1} Fahrenheit", c, UnitTransClass.C2F(this));
}
// 由于好奇,在这做了一个效率测试,想看看到底哪种方式访问成员变量更快,结论:区别不大。。。
public string Test1()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
this.value = i.ToString();
return string.Format("Have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
public string Test2()
{
long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
value = i.ToString();
return string.Format("Don't have this.: {0} MSEL", Environment.TickCount - vTickCount);
}
}
class UnitTransClass
{
public static double C2F(Class1 value)
{
// 摄氏到华氏的转换公式
return 1.8 * value.C + 32;
}
}
class Program
{
static void Main(string[] args)
{
Class1 tmpObj = new Class1(37.5);
Console.WriteLine(tmpObj);
Console.WriteLine(tmpObj.Test1());
Console.WriteLine(tmpObj.Test2());
Console.ReadLine();
}
}
}
结果:
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don't have this.: 4406 MSEL
11. 可以使用抽象函数重写基类中的虚函数吗?
答:可以,但需使用 new 修饰符显式声明,表示隐藏了基类中该函数的实现
示例 :
class BaseClass
{
public virtual void F()
{
Console.WriteLine("BaseClass.F");
}
}
abstract class DeriveClass : BaseClass
{
public new abstract void F();
}
12. 密封类可以有虚函数吗?
答:可以,基类中的虚函数将隐式的转化为非虚函数,但密封类本身不能再增加新的虚函数
示例:
class BaseClass
{
public virtual void F()
{
Console.WriteLine("BaseClass.F");
}
}
sealed class DeriveClass : BaseClass
{
// 基类中的虚函数 F 被隐式的转化为非虚函数
// 密封类中不能再声明新的虚函数 G
//public virtual void G()
//{
// Console.WriteLine("DeriveClass.G");
//}
}
13. 如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后可以有几个属性访问器?如果基类中有 get 和 set 两个呢?
答:如果基类中的虚属性只有一个属性访问器,那么继承类重写该属性后也应只有一个。如果基类中有 get 和 set 两个属性访问器,那么继承类中可以只有一个也可以同时有两个属性访问器
14.abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
答: abstract 修饰符不可以和 static 、 virtual 和 override 修饰符一起使用
15.
接口可以包含哪些成员?
答:接口可以包含属性、方法、索引指示器和事件,但不能包含常量、域、操作符、构造函数和析构函数,而且也不能包含任何静态成员
16. 类和结构的区别?
答:
答:接口可以包含属性、方法、索引指示器和事件,但不能包含常量、域、操作符、构造函数和析构函数,而且也不能包含任何静态成员
16. 类和结构的区别?
答:
类:类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存
.
类有构造和析构函数
.
类可以继承和被继承
结构:结构是值类型在栈上分配(虽然栈的访问速度比较堆要快,但栈的资源有限放),结构的赋值将分配产生一个新的对象。结构没有构造函数,但可以添加。结构没有析构函数 ,
结构:结构是值类型在栈上分配(虽然栈的访问速度比较堆要快,但栈的资源有限放),结构的赋值将分配产生一个新的对象。结构没有构造函数,但可以添加。结构没有析构函数 ,
结构不可以继承自另一个结构或被继承,但和类一样可以继承自接口
示例:
根据以上比较,我们可以得出一些轻量级的对象最好使用结构,但数据量大或有复杂处理逻辑对象最好使用类。
如: Geoemtry ( GIS 里的一个概论,在 OGC 标准里有定义) 最好使用类,而 Geometry 中点的成员最好使用结构
using System;
using System.Collections.Generic;
using System.Text;
namespace Example16
{
interface IPoint
{
double X
{
get;
set;
}
double Y
{
get;
set;
}
double Z
{
get;
set;
}
}
// 结构也可以从接口继承
struct Point: IPoint
{
private double x, y, z;
// 结构也可以增加构造函数
public Point(double X, double Y, double Z)
{
this.x = X;
this.y = Y;
this.z = Z;
}
public double X
{
get { return x; }
set { x = value; }
}
public double Y
{
get { return x; }
set { x = value; }
}
public double Z
{
get { return x; }
set { x = value; }
}
}
// 在此简化了点状 Geometry 的设计,实际产品中还包含 Project (坐标变换)等复杂操作
class PointGeometry
{
private Point value;
public PointGeometry(double X, double Y, double Z)
{
value = new Point(X, Y, Z);
}
public PointGeometry(Point value)
{
// 结构的赋值将分配新的内存
this.value = value;
}
public double X
{
get { return value.X; }
set { this.value.X = value; }
}
public double Y
{
get { return value.Y; }
set { this.value.Y = value; }
}
public double Z
{
get { return value.Z; }
set { this.value.Z = value; }
}
public static PointGeometry operator +(PointGeometry Left, PointGeometry Rigth)
{
return new PointGeometry(Left.X + Rigth.X, Left.Y + Rigth.Y, Left.Z + Rigth.Z);
}
public override string ToString()
{
return string.Format("X: {0}, Y: {1}, Z: {2}", value.X, value.Y, value.Z);
}
}
class Program
{
static void Main(string[] args)
{
Point tmpPoint = new Point(1, 2, 3);
PointGeometry tmpPG1 = new PointGeometry(tmpPoint);
PointGeometry tmpPG2 = new PointGeometry(tmpPoint);
tmpPG2.X = 4;
tmpPG2.Y = 5;
tmpPG2.Z = 6;
// 由于结构是值类型, tmpPG1 和 tmpPG2 的坐标并不一样
Console.WriteLine(tmpPG1);
Console.WriteLine(tmpPG2);
// 由于类是引用类型,对 tmpPG1 坐标修改后影响到了 tmpPG3
PointGeometry tmpPG3 = tmpPG1;
tmpPG1.X = 7;
tmpPG1.Y = 8;
tmpPG1.Z = 9;
Console.WriteLine(tmpPG1);
Console.WriteLine(tmpPG3);
Console.ReadLine();
}
}
}
结果:
X: 1, Y: 2, Z: 3
X: 4, Y: 5, Z: 6
X: 7, Y: 8, Z: 9
X: 7, Y: 8, Z: 9
17. 接口的多继承会带来哪些问题?
答: C# 中的接口与类不同,可以使用多继承,即一个子接口可以有多个父接口。但如果两个父成员具有同名的成员,就产生了二义性(这也正是 C# 中类取消了多继承的原因之一),这时在实现时最好使用显式的声明
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example17
{
class Program
{
// 一个完整的接口声明示例
interface IExample
{
// 属性
string P
{
get;
set;
}
// 方法
string F(int Value);
// 事件
event EventHandler E;
// 索引指示器
string this[int Index]
{
get;
set;
}
}
interface IA
{
int Count { get; set;}
}
interface IB
{
int Count();
}
//IC 接口从 IA 和 IB 多重继承
interface IC : IA, IB
{
}
class C : IC
{
private int count = 100;
// 显式声明实现 IA 接口中的 Count 属性
int IA.Count
{
get { return 100; }
set { count = value; }
}
// 显式声明实现 IB 接口中的 Count 方法
int IB.Count()
{
return count * count;
}
}
static void Main(string[] args)
{
C tmpObj = new C();
// 调用时也要显式转换
Console.WriteLine("Count property: {0}", ((IA)tmpObj).Count);
Console.WriteLine("Count function: {0}", ((IB)tmpObj).Count());
Console.ReadLine();
}
}
}
结果:
Count property: 100
Count function: 10000
示例:
根据以上比较,我们可以得出一些轻量级的对象最好使用结构,但数据量大或有复杂处理逻辑对象最好使用类。
如: Geoemtry ( GIS 里的一个概论,在 OGC 标准里有定义) 最好使用类,而 Geometry 中点的成员最好使用结构
using System;
using System.Collections.Generic;
using System.Text;
namespace Example16
{
interface IPoint
{
double X
{
get;
set;
}
double Y
{
get;
set;
}
double Z
{
get;
set;
}
}
// 结构也可以从接口继承
struct Point: IPoint
{
private double x, y, z;
// 结构也可以增加构造函数
public Point(double X, double Y, double Z)
{
this.x = X;
this.y = Y;
this.z = Z;
}
public double X
{
get { return x; }
set { x = value; }
}
public double Y
{
get { return x; }
set { x = value; }
}
public double Z
{
get { return x; }
set { x = value; }
}
}
// 在此简化了点状 Geometry 的设计,实际产品中还包含 Project (坐标变换)等复杂操作
class PointGeometry
{
private Point value;
public PointGeometry(double X, double Y, double Z)
{
value = new Point(X, Y, Z);
}
public PointGeometry(Point value)
{
// 结构的赋值将分配新的内存
this.value = value;
}
public double X
{
get { return value.X; }
set { this.value.X = value; }
}
public double Y
{
get { return value.Y; }
set { this.value.Y = value; }
}
public double Z
{
get { return value.Z; }
set { this.value.Z = value; }
}
public static PointGeometry operator +(PointGeometry Left, PointGeometry Rigth)
{
return new PointGeometry(Left.X + Rigth.X, Left.Y + Rigth.Y, Left.Z + Rigth.Z);
}
public override string ToString()
{
return string.Format("X: {0}, Y: {1}, Z: {2}", value.X, value.Y, value.Z);
}
}
class Program
{
static void Main(string[] args)
{
Point tmpPoint = new Point(1, 2, 3);
PointGeometry tmpPG1 = new PointGeometry(tmpPoint);
PointGeometry tmpPG2 = new PointGeometry(tmpPoint);
tmpPG2.X = 4;
tmpPG2.Y = 5;
tmpPG2.Z = 6;
// 由于结构是值类型, tmpPG1 和 tmpPG2 的坐标并不一样
Console.WriteLine(tmpPG1);
Console.WriteLine(tmpPG2);
// 由于类是引用类型,对 tmpPG1 坐标修改后影响到了 tmpPG3
PointGeometry tmpPG3 = tmpPG1;
tmpPG1.X = 7;
tmpPG1.Y = 8;
tmpPG1.Z = 9;
Console.WriteLine(tmpPG1);
Console.WriteLine(tmpPG3);
Console.ReadLine();
}
}
}
结果:
X: 1, Y: 2, Z: 3
X: 4, Y: 5, Z: 6
X: 7, Y: 8, Z: 9
X: 7, Y: 8, Z: 9
17. 接口的多继承会带来哪些问题?
答: C# 中的接口与类不同,可以使用多继承,即一个子接口可以有多个父接口。但如果两个父成员具有同名的成员,就产生了二义性(这也正是 C# 中类取消了多继承的原因之一),这时在实现时最好使用显式的声明
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example17
{
class Program
{
// 一个完整的接口声明示例
interface IExample
{
// 属性
string P
{
get;
set;
}
// 方法
string F(int Value);
// 事件
event EventHandler E;
// 索引指示器
string this[int Index]
{
get;
set;
}
}
interface IA
{
int Count { get; set;}
}
interface IB
{
int Count();
}
//IC 接口从 IA 和 IB 多重继承
interface IC : IA, IB
{
}
class C : IC
{
private int count = 100;
// 显式声明实现 IA 接口中的 Count 属性
int IA.Count
{
get { return 100; }
set { count = value; }
}
// 显式声明实现 IB 接口中的 Count 方法
int IB.Count()
{
return count * count;
}
}
static void Main(string[] args)
{
C tmpObj = new C();
// 调用时也要显式转换
Console.WriteLine("Count property: {0}", ((IA)tmpObj).Count);
Console.WriteLine("Count function: {0}", ((IB)tmpObj).Count());
Console.ReadLine();
}
}
}
结果:
Count property: 100
Count function: 10000
18. 抽象类和接口的区别?
答:
抽象类( abstract class )可以包含功能定义和实现,接口( interface )只能包含功能定义
抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性
分析对象,提炼内部共性形成抽象类,用以表示对象本质,即 “ 是什么 ” , 为外部提供调用或功能需要扩充时优先使用接口