面向对象总结

来源:互联网 发布:iframe跨域调用js方法 编辑:程序博客网 时间:2024/04/29 17:48

C#基础语法——对象、类和结构C# 是面向对象的编程语言,它使用类和结构来实现类型(如 Windows 窗体、用户界面控件和数据结构等)。典型的 C# 应用程序由程序员定义的类和 .NET Framework 的类组成。
C# 提供了许多功能强大的类定义方式,例如,提供不同的访问级别,从其他类继承功能,允许程序员指定实例化或销毁类型时的操作。
还可以通过使用类型参数将类定义为泛型,通过类型参数,客户端代码可以类型安全的有效方式来自定义类。客户端代码可以使用单个泛型类(例如,.NET Framework 类库中的 System.Collections.Generic.List )存储整数、字符串或任何其他类型的对象。
概述
对象、类和结构具有以下特点:

  • 对象是给定数据类型的实例。在执行应用程序时,数据类型为创建(或实例化)的对象提供蓝图。
  • 新数据类型是使用类和结构定义的。
  • 类和结构(包含代码和数据)组成了 C# 应用程序的生成块。C# 应用程序始终包含至少一个类。
  • 结构可视为轻量类,是创建用于存储少量数据的数据类型的理想选择,不能表示以后可能要通过继承进行扩展的类型。
  • C# 类支持继承,这意味着它们可以从先前定义的类中派生。

相关内容

  • 对象
  • 结构
  • 继承
  • 成员
  • 方法
  • 构造函数
  • 析构函数
  • 字段
  • 常数
  • 访问修饰符
  • 分部类定义
  • 静态类和静态类成员

  




对象

对象是具有数据、行为和标识的编程结构。对象数据包含在对象的字段、属性和事件中,对象行为则由对象的方法和接口定义。
对象具有标识 -- 数据集相同的两个对象不一定是同一对象。
C# 中的对象通过 classes structs 定义 -- 该类型的所有对象都按照它们构成的同一蓝图操作。


对象具有以下特点:

  • C# 中使用的全都是对象,包括 Windows 窗体和控件。
  • 对象是实例化的;也就是说,对象是从类和结构所定义的模板中创建的。
  • 对象使用 属性 获取和更改它们所包含的信息。
  • 对象通常具有允许它们执行操作的方法和事件。
  • Visual Studio 提供了操作对象的工具:使用 “属性”窗口 可以更改对象(如 Windows 窗体)的属性。使用 对象浏览器 可以检查对象的内容。
  • 所有 C# 对象都继承自 Object

  








结构

结构是使用 struct 关键字定义的,例如:
C# public struct PostalAddress
{
// Fields, properties, methods and events go here...
}

结构与类共享几乎所有相同的语法,但结构比类受到的限制更多:

  • 尽管结构的静态字段可以初始化,结构实例字段声明还是不能使用初始值设定项。
  • 结构不能声明默认构造函数(没有参数的构造函数)或析构函数。

结构的副本由编译器自动创建和销毁,因此不需要使用默认构造函数和析构函数。实际上,编译器通过为所有字段赋予默认值(参见 默认值表 )来实现默认构造函数。结构不能从类或其他结构继承。
结构是值类型 -- 如果从结构创建一个对象并将该对象赋给某个变量,变量则包含结构的全部值。复制包含结构的变量时,将复制所有数据,对新副本所做的任何修改都不会改变旧副本的数据。由于结构不使用引用,因此结构没有标识 -- 具有相同数据的两个值类型实例是无法区分的。C# 中的所有值类型本质上都继承自 ValueType ,后者继承自 Object
编译器可以在一个称为装箱的过程中将值类型转换为引用类型。有关更多信息,请参见 装箱和取消装箱
结构概述 结构具有以下特点:

  • 结构是值类型,而类是引用类型。
  • 向方法传递结构时,结构是通过传值方式传递的,而不是作为引用传递的。
  • 与类不同,结构的实例化可以不使用 new 运算符。
  • 结构可以声明构造函数,但它们必须带参数。
  • 一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType ,后者继承自 System.Object
  • 结构可以实现接口。
  • 在结构中初始化实例字段是错误的。

struct 类型适于表示 Point Rectangle Color 等轻量对象。尽管可以将一个点表示为 ,但在某些情况下,使用 结构 更有效。例如,如果声明一个 1000 个 Point 对象组成的数组,为了引用每个对象,则需分配更多内存;这种情况下,使用结构可以节约资源。由于 .NET Framework 包含名为 Point 的对象,因此我们转而调用结构“CoOrds”。
C# public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}

声明结构的默认(无参数)构造函数是错误的。总是提供默认构造函数以将结构成员初始化为它们的默认值。在结构中初始化实例字段也是错误的。
如果使用 new 运算符创建结构对象,则会创建该结构对象,并调用适当的构造函数。与类不同,结构的实例化可以不使用 new 运算符。如果不使用 new ,则在初始化所有字段之前,字段都保持未赋值状态且对象不可用。
对于结构,不像类那样存在继承。一个结构不能从另一个结构或类继承,而且不能作为一个类的基。但是,结构从基类 Object 继承。结构可实现接口,其方式同类完全一样。
与 C++ 不同,无法使用 struct 关键字声明类。在 C# 中,类与结构在语义上是不同的。结构是值类型,而类是引用类型。有关更多信息,请参见 值类型
除非需要引用类型语义,否则系统将较小的类作为结构处理效率会更高。
示例 1

说明 下面的示例演示使用默认构造函数和参数化构造函数的 struct 初始化。
代码 C# public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}
// Declare and initialize struct objects.
class TestCoOrds
{
static void Main()
{
// Initialize:
CoOrds coords1 = new CoOrds();
CoOrds coords2 = new CoOrds(10, 10);
// Display results:
System.Console.Write("CoOrds 1: ");
System.Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
System.Console.Write("CoOrds 2: ");
System.Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y);
}
}
输出

CoOrds 1: x = 0, y = 0
CoOrds 2: x = 10, y = 10







继承
类可以从其他类中继承。这是通过以下方式实现的:在声明类时,在类名称后放置一个冒号,然后在冒号后指定要从中继承的类(即基类)。例如:
C# public class A
{
public A() { }
}
public class B : A
{
public B() { }
}

新类(即派生类)将获取基类的所有非私有数据和行为以及新类为自己定义的所有其他数据或行为。因此,新类具有两个有效类型:新类的类型和它继承的类的类型。
在上面的示例中,类 B 既是有效的 B,又是有效的 A。访问 B 对象时,可以使用强制转换操作将其转换为 A 对象。强制转换不会更改 B 对象,但您的 B 对象视图将限制为 A 的数据和行为。将 B 强制转换为 A 后,可以将该 A 重新强制转换为 B。并非 A 的所有实例都可强制转换为 B,只有实际上是 B 的实例的那些实例才可以强制转换为 B。如果将类 B 作为 B 类型访问,则可以同时获得类 A 和类 B 的数据和行为。对象可以表示多个类型的能力称为多态性。
结构不能从其他结构或类中继承。类和结构都可以从一个或多个接口中继承。
抽象类、密封类及类成员
使用 abstract 关键字可以创建仅用于继承用途的类和 成员,即定义派生的非抽象类的功能。使用 sealed 关键字可以防止继承以前标记为 virtual 的类或某些类成员。有关更多信息,请参见 如何:定义抽象属性(C# 编程指南)
抽象类和类成员

可以将类声明为抽象类。方法是在类定义中将关键字 abstract 置于关键字 class 的前面。例如:
C# public abstract class A
{
// Class members here.
}
抽象类不能实例化。抽象类的用途是提供多个派生类可共享的基类的公共定义。例如,类库可以定义一个作为其多个函数的参数的抽象类,并要求程序员使用该库通过创建派生类来提供自己的类实现。
抽象类也可以定义抽象方法。方法是将关键字 abstract 添加到方法的返回类型的前面。
抽象方法没有实现,所以方法定义后面是分号,而不是常规的方法块。抽象类的派生类必须实现所有抽象方法。当抽象类从基类继承虚方法时,抽象类可以使用抽象方法重写该虚方法。
如果将虚方法声明为抽象方法,则它对于从抽象类继承的所有类而言仍然是虚的。继承抽象方法的类无法访问该方法的原始实现。在前面的示例中,类 F 上的 DoWork 无法调用类 D 上的 DoWork 。在此情况下,抽象类可以强制派生类为虚方法提供新的方法实现。
密封类和类成员

可以将类声明为密封类。方法是在类定义中将关键字 sealed 置于关键字 class 的前面。例如:
C# public sealed class D
{
// Class members here.
}
密封类不能用作基类。因此,它也不能是抽象类。密封类主要用于防止派生。由于密封类从不用作基类,所以有些运行时优化可以使对密封类成员的调用略快。
在对基类的虚成员进行重写的派生类上的类成员、方法、字段、属性或事件可以将该成员声明为密封成员。在用于以后的派生类时,这将取消成员的虚效果。方法是在类成员声明中将 sealed 关键字置于 override 关键字的前面。例如:
C# public class D : C
{
public sealed override void DoWork() { }
}
  




接口是使用 interface 关键字定义的。例如:
C# interface IComparable
{
int CompareTo(object obj);
}
接口描述可属于任何 结构 的一组相关行为。接口可由方法、属性、事件、索引器或这四种成员类型的任何组合构成。接口不能包含字段。接口成员一定是公共的。
类和结构可以像类继承基类或结构一样从接口继承,但有两个例外:

  • 类或结构可继承多个接口。
  • 当类或结构继承接口时,它继承成员定义但不继承实现。例如:

C# public class Minivan : Car, IComparable
{
public int CompareTo(object obj)
{
//implementation of CompareTo
return 0; //if the Minivans are equal
}
}
若要实现接口成员,类中的对应成员必须是公共的、非静态的,并且与接口成员具有相同的名称和签名。类的属性和索引器可以为接口上定义的属性或索引器定义额外的访问器。例如,接口可以声明一个带有 get 访问器的属性,而实现该接口的类可以声明同时带有 get set 访问器的同一属性。但是,如果属性或索引器使用显式实现,则访问器必须匹配。
接口和接口成员是抽象的;接口不提供默认实现。有关更多信息,请参见 抽象类、密封类和类成员
IComparable 接口向对象的用户宣布该对象可以将自身与同一类型的其他对象进行比较,接口的用户不需要知道相关的实现方式。
接口可以继承其他接口。类可以通过其继承的基类或接口多次继承某个接口。在这种情况下,如果将该接口声明为新类的一部分,则类只能实现该接口一次。如果没有将继承的接口声明为新类的一部分,其实现将由声明它的基类提供。基类可以使用虚拟成员实现接口成员;在这种情况下,继承接口的类可通过重写虚拟成员来更改接口行为。
接口概述

接口具有下列属性:

  • 接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
  • 不能直接实例化接口。
  • 接口可以包含事件、索引器、方法和属性。
  • 接口不包含方法的实现。
  • 类和结构可从多个接口继承。
  • 接口自身可从多个接口继承


如果 实现两个接口,并且这两个接口包含具有相同签名的成员,那么在类中实现该成员将导致两个接口都使用该成员作为它们的实现。例如:
C# interface IControl
{
void Paint();
}
interface ISurface
{
void Paint();
}
class SampleClass : IControl, ISurface
{
// Both ISurface.Paint and IControl.Paint call this method.
public void Paint()
{
}
}
然而,如果两个 接口 成员执行不同的函数,那么这可能会导致其中一个接口的实现不正确或两个接口的实现都不正确。可以显式地实现接口成员 -- 即创建一个仅通过该接口调用并且特定于该接口的类成员。这是使用接口名称和一个句点命名该类成员来实现的。例如:
C# public class SampleClass : IControl, ISurface
{
void IControl.Paint()
{
System.Console.WriteLine("IControl.Paint");
}
void ISurface.Paint()
{
System.Console.WriteLine("ISurface.Paint");
}
}类成员 IControl.Paint 只能通过 IControl 接口使用, ISurface.Paint 只能通过 ISurface 使用。两个方法实现都是分离的,都不可以直接在类中使用。例如:
C# SampleClass obj = new SampleClass();
//obj.Paint(); // Compiler error. IControl c = (IControl)obj;
c.Paint(); // Calls IControl.Paint on SampleClass.
ISurface s = (ISurface)obj;
s.Paint(); // Calls ISurface.Paint on SampleClass.
显式实现还用于解决两个接口分别声明具有相同名称的不同成员(如属性和方法)的情况:
C# interface ILeft
{
int P { get;}
}
interface IRight
{
int P();
}为了同时实现两个接口,类必须对属性 P 和/或方法 P 使用显式实现以避免编译器错误。例如:
C# class Middle : ILeft, IRight
{
public int P() { return 0; }
int ILeft.P { get { return 0; } }
}

原创粉丝点击