C#面向对象——继承
1.继承
1.基本概念
一个类A继承类B,类B称为父类(基类、超类),类A被称为子类(派生类)。类A将会拥有B类的所有成员以及所有特征和行为。
注意:子类可以有自己的特征和行为
2.基本语法
class 父类米名
{
}
class 子类名: 父类名
{
}
3.特点:
1.单根性:子类只能有一个父类
2.传递性:子类可以间接继承父类的父类(子类下面可以有n个子类)
// 基类/父类
public class Animal
{
public string Name { get; set; }
public int Age { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}
// 派生类/子类
public class Dog : Animal // 使用冒号表示继承
{
public string Breed { get; set; }
public void Bark()
{
Console.WriteLine("Woof! Woof!");
}
}
4.受访问修饰符的影响
1.public 公有的
2.private 私有的,在外部和子类都不可以被访问
3.protected 保护的,内部和子类可以访问,外部不可以访问
5.子类和父类同名的成员
C#中允许子类和父类存在同名的成员,但不建议使用。
class P1
{
public string name;
}
class P2: P1
{
// public string name; // 不建议这样写
public new string name; // (建议这样写)使用new隐藏父类字段,覆盖了父类同名的成员
}
// 实例化
var obj = new P2();
obj.name = "子类值"; // 访问 P2.name
// (P1)obj:类型转换,显式转换将P2类型转换成P1类型
((P1)obj).name = "父类值"; // 访问 P1.name
2.里氏替换原则
1.概念:
任何父类出现的地方,子类都可以替代。
语法表现——父类容器装子类,因为子类对象包括了父类的所有内容
作用: 方便进行对象的存储和管理
2.实例
class Gameobject
{
}
class Player: Gameobject
{
public void PlayerPrint()
{
Console.WriteLine("玩家");
}
}
class Boss: Gameobject
{
public void BossPirnt()
{
Console.WriteLine("Boss");
}
}
// 里氏替换原则(用父类容器装载子类对象)
Gameobject player = new Player();
Gameobject boss = new Boss();
// 初始化对象数组
GameObject[] objects = new GamneObject(new Player(), new Boss());
3.is 和 as(一般配合使用)
1.is 基本概念
is 判断一个对象是否是指定类对象,返回值是bool类型
对象 is 类型
class Player
{
}
Player player = new Player();
if(player is Player)
{
}
object obj = "Hello";
if (obj is string) // 检查是否为string类型
{
Console.WriteLine("obj是字符串");
}
if (obj is int) // 检查是否为int类型
{
Console.WriteLine("obj是整数");
}
2.as 基本概念
as (只能用于引用类型或空值类型),将一个对象转换成指定类对象
返回值:转换成功返回转换成功的对象,转换失败返回null
补充:可空值类型是 C# 中用于表示"可能有值,也可能为 null"的值类型的特殊结构。
// 可空值类型
类型? 变量名;
// 等价于
Nullable<类型> 变量名;
// 引用类型转换
object obj = "Hello";
string str = obj as string; // ✅ 合法:string是引用类型
// 可空值类型转换
object num = 42; // object 所有类型的终级基类
int? nullableInt = num as int?; // ✅ 合法:int?是可空值类型
3.继承中的构造函数
1.构造函数概念
实例化对象时调用的函数,主要是用来初始化成员变量的,每一个类都会有一个默认的无参构造函数
2.继承中的构造函数
1.特点:当声明了一个子类对象时,先执行父类的构造函数,再执行子类的构造函数
2.注意:
1.父类的无参构造函数很重要(子类必须调用父类的构造函数(直接或间接))
2.子类可以通过 base 关键字代表父类调用父类的构造函数(显式指定)
3.不能在同一个构造函数中多次使用base
4.父类的无参构造函数很重要。子类实例化时,默认自动调用的是父类的无参构造函数,所有如果父类无参构造函数被覆盖了,则子类无法调用父类的无参构造函数(报错)。所有当父类的无参构造函数被覆盖时,要显式指定(base)调用哪个构造函数
class Parent
{
public Parent(int id) { } // 带参构造
public Parent(string name) { }
}
class Child1 : Parent
{
public Child() { } // ❌ 编译错误
}
class Child2 : Parent
{
public Child() : base(0) { } // ✅ 显式传参
}
class Child3 : Parent
{
public Child(int id) : base(id) { } // ✅ 参数传递给父类
public Child(int id) : base(string name), base(id) { } // ❌ 错误!不能多次调用不同的基类构造函数
}
base:调用父类的构造函数
this:调用当前类其他构造函数(构造函数的链式调用)
4.万物之父
1.基本概念
object是所有类型的基类,它是一个引用类型
关键字:object
作用:
1.可以利用里氏替换原则,用object容器装载所有对象
2.可以用来表示不确定类型,作为函数参数类型
// 显式继承
class MyClass : Object { }
// 隐式继承(编译器自动添加)
class MyClass { } // 等价于 class MyClass : Object
// 值类型也继承自Object
struct MyStruct { } // 结构体也继承自Object
// 甚至基本类型也继承自Object
int number = 42;
string text = "hello";
class Father
{
}
clas Son: Father
{
}
static void Main(string[] args)
{
Object obj = new Son();
}
2.装箱和拆箱
1.装箱:将值类型转换为引用类型(object或接口类型)的过程
过程:
1.在堆(heap)上分配内存
2.将值类型的值复制到堆上新分配的对象中
3.返回新对象的引用
2.拆箱:将引用类型转换回值类型的过程
过程:
1.检查对象实例是否为给定值类型的装箱值
2.将值从实例复制到值类型变量中
int i = 123; // 值类型
object o = i; // 装箱 - 将int装箱到object中
int j = (int)o; // 拆箱 - 将object拆箱回int
3.好处与坏处
好处:不确定类型时可以方便参数的存储和传递
坏处:存在内存迁移,增加了性能消耗
5.密封类和密封方法
1.密封类基本概念:
使用 sealed 关键字修饰的类。该类无法被继承。在面向对象程序设计中,密封类的主要作用就是不允许最底层子类被继承。可以保证程序的规范性、安全性。加强了程序设计的结构性、安全性。
// 基本语法
访问修饰符 sealed class Person
{
}
sealed class Person
{
}
2.密封方法的基本概念:
使用 sealed 关键字修饰的方法,该方法不能被重写。
注意:sealed关键字不能直接用于普通方法,只能用于 重写的方法(override)。也就是说不能直接定义密封方法。只能重写时,对其进行密封。
public class BaseClass
{
// 普通方法
public virtual void NormalMethod() { }
public virtual void MethodToSeal() { }
}
public class DerivedClass : BaseClass
{
// 可以重写普通虚方法
public override void NormalMethod() { }
// 重写并密封方法 - 后续派生类不能再重写此方法
public sealed override void MethodToSeal() { }
}
public class FurtherDerivedClass : DerivedClass
{
public override void NormalMethod() { } // ✅ 可以重写
// ❌ 编译错误:无法重写密封方法
// public override void MethodToSeal() { }
}
更多推荐



所有评论(0)