文章目录
7.2.1 类的概念
类(Class)是面向对象编程(OOP)中的核心概念之一,它作为创建对象的模板或蓝图,定义了对象的属性(数据)和方法(行为)。以下是类的一些关键特性和组成:
类的关键特性
-
抽象:类是对现实世界中事物的抽象,它定义了事物的通用特征和行为。
-
封装:类将数据和操作这些数据的方法组合在一起,并隐藏内部的实现细节,只对外提供有限的接口。
-
继承:类可以通过继承机制复用代码,子类可以继承父类的属性和方法。
-
多态:类可以实现多态性,即同一个方法在不同的对象中可以有不同的实现。
类的组成
-
数据成员
- 常量:在类中不会被修改的变量。
- 域(Field):类中用于存储数据的变量。
-
函数成员
- 方法(Method):类中定义的函数,用于执行类的行为。
- 属性(Property):用于控制对类中字段的访问。
- 事件(Event):用于处理对象间的通信。
- 索引器(Indexer):允许对象被索引,就像数组一样。
- 运算符(Operator):允许对类类型使用标准的C#运算符。
- 构造函数:用于初始化新创建的对象。
- 实例构造函数:初始化非静态成员。
- 静态构造函数:初始化静态成员。
- 析构函数(Destructor):在对象被销毁前执行清理工作。
-
嵌套类型:类中可以定义的其他类或结构。
示例代码
以下是C#中定义一个简单的类的例子:
using System;
// 定义一个类
public class Person
{
// 数据成员
private string name;
public int Age { get; set; }
// 函数成员
public void Eat()
{
Console.WriteLine("Eating");
}
public void Sleep()
{
Console.WriteLine("Sleeping");
}
// 构造函数
public Person(string name)
{
this.name = name;
}
// 静态构造函数
static Person()
{
Console.WriteLine("Static constructor executed.");
}
// 嵌套类型
public class InnerClass
{
public void Display()
{
Console.WriteLine("Inner class method.");
}
}
}
public class Program
{
public static void Main()
{
// 创建Person类的实例
Person person = new Person("Alice");
person.Eat();
person.Sleep();
// 创建嵌套类的实例
Person.InnerClass innerClass = new Person.InnerClass();
innerClass.Display();
}
}
在这个示例中,Person
类有两个数据成员(name
和Age
),两个方法(Eat
和Sleep
),一个构造函数,一个静态构造函数和一个嵌套类型(InnerClass
)。Main
方法展示了如何创建Person
对象和InnerClass
对象的实例。
类是面向对象编程中实现封装和抽象的基础,是构建软件时组织代码的逻辑单元。
7.2.2 类的声明
在C#中,可以通过类修饰符来控制类的可见性和可访问性。以下是一些常用的类修饰符:
-
public
- 描述:类可以被任何其他类访问。
- 例如:
public class Car { ... }
-
private
- 描述:类只能在定义它的程序集中访问。
- 例如:
private class Car { ... }
(不常用,因为通常嵌套类使用private)
-
internal
- 描述:类只在当前程序集中可访问。
- 例如:
internal class Car { ... }
-
protected
- 描述:类可以被定义它的类以及其派生类访问(不常用于类本身,常用于成员)。
- 例如:
protected class Car { ... }
(不常用,因为通常继承中使用protected)
-
static
- 描述:类不能实例化,所有成员都是静态的。
- 例如:
static class Car { ... }
-
sealed
- 描述:类不能被继承。
- 例如:
public sealed class Car { ... }
-
abstract
- 描述:类不能被实例化,它可能包含未实现的方法(抽象方法),这些方法必须在派生类中实现。
- 例如:
public abstract class Car { ... }
-
partial
- 描述:类的定义被拆分到多个代码文件中,这在大型项目中很常见。
- 例如:
public partial class Car { ... }
示例代码:定义汽车类
以下是定义一个简单的汽车类的例子:
public class Car
{
public string Color { get; set; }
public string Brand { get; set; }
public int Year { get; set; }
public Car(string brand, string color, int year)
{
Brand = brand;
Color = color;
Year = year;
}
public void StartEngine()
{
Console.WriteLine("Engine started!");
}
}
在这个示例中,Car
类被声明为public
,这意味着它可以在任何地方被访问。它有3个自动实现的属性:Color
、Brand
和Year
,以及一个方法StartEngine
。
继承方式
在C#中,当一个类继承自另一个类时,可以使用下面的修饰符:
-
: base
- 描述:冒号(:)表示继承,后面跟着基类名。
- 例如:
public class SportsCar : Car { ... }
-
virtual
- 描述:在基类中,将方法声明为virtual,允许在派生类中被重写。
- 例如:
public virtual void StartEngine() { ... }
-
override
- 描述:在派生类中,用于重写基类中的virtual方法。
- 例如:
public override void StartEngine() { ... }
-
new
- 描述:用于隐藏继承的同名成员。
- 例如:
public new string Color { get; set; }
-
abstract
- 描述:在抽象基类中,将方法声明为抽象,迫使派生类实现它。
- 例如:
public abstract void StartEngine();
-
sealed
- 描述:阻止方法在派生类中被重写。
- 例如:
public sealed override void StartEngine() { ... }
继承是面向对象编程中的一个重要概念,它允许代码的重用和扩展。
7.2.3 类的成员
在C#中,类的成员是可以由类的对象(实例)或类本身来调用的元素。以下是类成员的详细分类和描述:
局部变量
- 描述:局部变量是在方法、构造函数或块内部声明的变量,它们只在这些范围内有效。
- 示例:
void DisplayMessage() { string message = "Hello"; Console.WriteLine(message); }
字段
-
描述:字段是类中声明的变量,可以是静态的(类级别)或实例的(对象级别)。
- 静态字段:属于类,而不是类的任何特定对象。
- 实例字段:每个对象实例拥有自己的副本。
- 常量:字段值在初始化后不能改变。
- 只读字段:字段可以在构造函数中初始化一次,之后不能修改。
-
示例:
public class Person { public const int MaxPersons = 100; // 常量 public string Name; // 实例字段 private int _age; // 私有实例字段 public readonly int ID; // 只读字段 }
方法成员
-
描述:方法包含执行特定任务的代码。
- 静态方法:通过类直接调用,不依赖于类的实例。
- 实例方法:需要类的实例来调用。
-
示例:
public class Calculator { public static int Add(int a, int b) // 静态方法 { return a + b; } public int Multiply(int a, int b) // 实例方法 { return a * b; } }
属性
- 描述:属性提供了访问类中字段的安全方式,可以有
get
和set
块。 - 示例:
public class Product { private string _name; public string Name { get { return _name; } set { _name = value; } } }
事件
- 描述:事件是一种特殊的多播委托,用于类之间的松散耦合。
- 示例:
public class Publisher { public event EventHandler UpdateEvent; public void DoSomething() { UpdateEvent?.Invoke(this, EventArgs.Empty); } }
索引指示器
- 描述:允许对象被像数组一样通过索引访问。
- 示例:
public class ListDictionary { private Dictionary<int, string> _dictionary = new Dictionary<int, string>(); public string this[int index] { get { return _dictionary[index]; } set { _dictionary[index] = value; } } }
操作符重载
- 描述:允许已定义的类使用特定的C#操作符。
- 示例:
public class Point { public int X, Y; public static Point operator +(Point p1, Point p2) { return new Point { X = p1.X + p2.X, Y = p1.Y + p2.Y }; } }
构造函数和析构函数
-
描述:
- 构造函数:在创建对象时初始化对象的方法,可以有多个(带不同参数)。
- 析构函数:在对象被销毁前执行的方法,用来执行清理工作。
-
示例:
public class Car { public Car() { Console.WriteLine("Car is created."); } ~Car() { Console.WriteLine("Car is destroyed."); } }
示例代码:组合类成员
以下是组合使用类成员的示例:
using System;
public class Car
{
public string Brand { get; set; }
private int _year;
public int Year
{
get { return _year; }
set { _year = value > 0 ? value : throw new ArgumentException("Year must be positive."); }
}
public Car(string brand, int year)
{
Brand = brand;
Year = year;
}
public void StartEngine()
{
Console.WriteLine("Engine started.");
}
public event EventHandler Started;
protected virtual void OnStarted()
{
Started?.Invoke(this, EventArgs.Empty);
}
public override string ToString()
{
return $"Car: {Brand}, Year: {Year}";
}
}
public class Program
{
public static void Main()
{
Car myCar = new Car("Toyota", 2021);
myCar.Started += (sender, e) => Console.WriteLine("Car event started.");
myCar.StartEngine();
Console.WriteLine(myCar);
}
}
在这个示例中,Car
类使用了属性、方法、事件、构造函数和析构函数等类成员。Main
方法展示了如何创建和使用Car
对象。
7.2.4 类成员访问修饰符
在C#中,类成员访问修饰符用于控制类成员的可访问性。以下是常用的类成员访问修饰符及其描述:
修饰符 | 描述 |
---|---|
private | 私有成员只能在定义它的类内部访问。 |
protected | 保护成员可以在定义它的类及其派生类中访问。 |
public | 公共成员可以被任何其他类或实例访问。 |
internal | 内部成员只能在同一个程序集中访问。 |
访问修饰符的示例代码
以下是使用这些访问修饰符的示例:
public class Animal
{
// 私有字段,只能在Animal类内部访问
private string privateName;
// 保护字段,可以在Animal类及其派生类中访问
protected string protectedName;
// 公共属性,可以被任何类访问
public string PublicName { get; set; }
// 内部字段,只能在同一个程序集中访问
internal string InternalHabitat;
// 私有方法,只能在Animal类内部调用
private void PrivateMethod()
{
Console.WriteLine("Private method.");
}
// 保护方法,可以在Animal类及其派生类中调用
protected void ProtectedMethod()
{
Console.WriteLine("Protected method.");
}
// 公共方法,可以被任何类调用
public void PublicMethod()
{
Console.WriteLine("Public method.");
}
// 内部方法,只能在同一个程序集中调用
internal void InternalMethod()
{
Console.WriteLine("Internal method.");
}
}
public class Dog : Animal
{
public Dog()
{
// 可以访问继承的保护成员和公有成员
protectedName = "Canine";
PublicName = "Dog";
// 不能直接访问私有成员,但可以通过公共或保护方法间接访问
PrivateMethod();
}
protected void ShowProtectedMethod()
{
ProtectedMethod();
}
}
public class Program
{
public static void Main()
{
Animal myAnimal = new Animal();
Dog myDog = new Dog();
// 可以访问公有成员
myAnimal.PublicName = "Animal";
// 不能直接访问私有成员或保护成员
//privateName = "Incorrect";
//protectedName = "Incorrect";
// 内部成员只能在同一个程序集中访问
//Animal internalAnimal = new Animal();
//internalAnimal.InternalHabitat = "Incorrect";
}
}
说明
-
私有成员(
private
):只能在定义它的类内部访问。例如,privateName
只能在Animal
类内部访问。 -
保护成员(
protected
):可以在定义它的类及其派生类中访问。例如,protectedName
可以在Animal
类及其派生类如Dog
中访问。 -
公共成员(
public
):可以被任何其他类或实例访问。例如,PublicName
属性可以被任何类访问和修改。 -
内部成员(
internal
):只能在同一个程序集中访问。例如,InternalHabitat
只能在同一个程序集中的其他类中访问。
派生类访问基类成员
派生类可以继承基类的成员,但访问级别取决于基类成员的访问修饰符:
- 私有成员(
private
):不能被派生类直接访问。 - 保护成员(
protected
):可以在派生类中访问。 - 公共成员(
public
):可以在派生类中访问。 - 内部成员(
internal
):如果派生类在同一个程序集中,可以访问。
这些访问修饰符提供了封装和信息隐藏的机制,有助于保护类成员不被外部直接访问和修改,从而提高代码的安全性和可维护性。