14.C# —— 静态成员、只读常量、继承、访问修饰符、多态、抽象类

目录

一、静态成员(static)

[1. 核心概念](#1. 核心概念)

[2. 调用规则](#2. 调用规则)

完整代码示例

[3. 静态成员共享特性测试](#3. 静态成员共享特性测试)

二、只读(readonly)与常量(const)

核心区别

完整代码

三、类的继承

[1. 继承基础规则](#1. 继承基础规则)

[2. 访问权限(继承相关)](#2. 访问权限(继承相关))

完整代码

四、父子类构造函数执行顺序

核心规则

完整代码

五、五大访问修饰符

权限对照表

[1. 本项目测试代码](#1. 本项目测试代码)

[2. 跨项目测试代码(引用上方命名空间)](#2. 跨项目测试代码(引用上方命名空间))

六、多态:函数重载(静态多态)

[1. 多态分类](#1. 多态分类)

[2. 函数重载条件(必须全部满足)](#2. 函数重载条件(必须全部满足))

代码示例

七、运算符重载

规则

完整代码(盒子对象运算)

八、抽象类(abstract)

核心特点

完整代码

总结


一、静态成员(static)

1. 核心概念

  1. 非静态成员 :属于对象(实例) ,每个对象拥有独立的数据,必须 new 实例后调用。
  2. 静态成员 :属于类本身 ,全局共享一份数据,通过 类名.成员 直接调用,所有实例共用。

2. 调用规则

  • 非静态方法:可以访问 静态 / 非静态 成员
  • 静态方法:只能访问静态成员,不能直接调用实例成员(需手动创建对象)

完整代码示例

cs 复制代码
using System;

namespace _2静态成员
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 非静态成员:实例对象调用
            People p1 = new People();
            p1.F1();
            p1.Id = 1;

            // 静态成员:类名直接调用
            People.Age = 10;
            People.F2();
        }
    }

    public class People
    {
        // 非静态字段 + 属性
        private int id;
        public int Id
        {
            get { return id; }
            set
            {
                Console.WriteLine("给Id赋值");
                id = value; 
                // 禁止写 Id = value,会造成属性死递归
            }
        }

        // 非静态方法
        public void F1()
        {
            Console.WriteLine("非静态方法 F1");
        }

        // 静态自动属性
        public static int Age { get; set; }

        // 静态方法
        public static void F2()
        {
            Console.WriteLine("静态方法 F2");
        }
    }
}

3. 静态成员共享特性测试

静态属性全局共享,一个实例修改,所有实例读取到的值都会变化:

cs 复制代码
using System;

namespace _3静态成员测试
{
    internal class Program
    {
        static void Main(string[] args)
        {
            People p1 = new People();
            p1.AddNum();

            People p2 = new People();
            p2.AddNum();

            // 静态Num全局共享,结果均为 2
            Console.WriteLine(p1.GetNum());
            Console.WriteLine(p2.GetNum());
        }
    }

    public class People
    {
        public int Age { get; set; }
        public static int Num { get; set; }

        public void AddNum()
        {
            Num++;
        }

        public int GetNum()
        {
            return Num;
        }
    }
}

二、只读(readonly)与常量(const)

核心区别

  1. const 常量
    • 编译时常量,隐式 static,必须定义时直接赋值
    • 全局不能修改,通过 类名.常量名 访问
  2. readonly 只读字段
    • 运行时常量,分实例只读静态只读
    • 实例只读:只能在实例构造函数中赋值
    • 静态只读:只能在静态构造函数中赋值
  3. 静态构造函数
    • 无访问修饰符、无参数
    • 全局仅执行一次,首次使用类 / 创建实例时触发

完整代码

cs 复制代码
using System;

namespace _4只读和常量
{
    internal class Program
    {
        static void Main(string[] args)
        {
            People p1 = new People();
            // p1.a = 30; 报错:只读字段不能在构造函数外修改

            Console.WriteLine(People.b);
            Console.WriteLine(People.c);
        }
    }

    public class People
    {
        // 实例只读字段
        public readonly int a = 10;
        // 静态只读字段
        public static readonly int b = 20;
        // 常量(隐式static)
        public const int c = 30;

        // 实例构造函数:修改实例只读 a
        public People()
        {
            a = 20;
            Console.WriteLine(a);
        }

        // 静态构造函数:修改静态只读 b,仅执行一次
        static People()
        {
            b = 40;
            Console.WriteLine(b);
        }
    }
}

三、类的继承

1. 继承基础规则

  • 语法:子类 : 父类
  • C# 为单继承:一个类只能直接继承一个父类,支持链式继承
  • 所有类默认隐式继承 object(顶级基类)
  • 作用:代码复用、拓展功能

2. 访问权限(继承相关)

  • private 私有:仅当前类内部访问,子类无法继承
  • protected 受保护:当前类 + 子类可访问,外部实例无法访问
  • public 公共:全场景可访问

完整代码

cs 复制代码
using System;

namespace _5继承
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Student s1 = new Student();
            s1.Name = "Test";
            s1.Address = "地址";
            s1.F1();
        }
    }

    // 父类
    public class People
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }

        // 私有成员:子类不可访问
        private int Age = 1000;
        // 受保护成员:子类可访问,外部实例不可访问
        protected int CC { get; set; }

        public void F1()
        {
            Console.WriteLine("父类方法 F1");
        }
    }

    // 子类 Student 继承父类 People
    public class Student : People
    {
        public void F2()
        {
            // 继承父类 public / protected 成员
            Console.WriteLine($"{Name} {Id} {CC}");
        }
    }
}

四、父子类构造函数执行顺序

核心规则

  1. 创建子类对象时,优先执行父类构造函数,再执行子类构造
  2. 默认自动调用父类无参构造 ,可通过 base(参数) 指定调用父类有参构造
  3. 简写总结:
    • 子类构造不写 base → 父类必须有无参构造
    • 子类构造写 base(参数) → 父类可省略无参构造

完整代码

cs 复制代码
using System;

namespace _6子类构造和父类构造执行顺序
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 先执行父类有参构造 → 再执行子类有参构造
            Student s2 = new Student(10, "张三");
        }
    }

    public class People
    {
        public string Name { get; set; }

        // 父类无参构造
        public People()
        {
            Console.WriteLine("父类无参构造");
        }

        // 父类有参构造
        public People(string name)
        {
            Name = name;
            Console.WriteLine("父类有参构造");
        }
    }

    public class Student : People
    {
        public int Age { get; set; }

        // base() 可省略,默认调用父类无参构造
        public Student() : base()
        {
            Console.WriteLine("子类无参构造");
        }

        // base(n) 主动调用父类有参构造
        public Student(int age, string n) : base(n)
        {
            Age = age;
            Console.WriteLine("子类有参构造:" + Name);
        }
    }
}

五、五大访问修饰符

权限对照表

修饰符 本类 子类 本项目实例 跨项目子类 跨项目实例
public
private
protected
internal
protected internal

1. 本项目测试代码

cs 复制代码
using System;

namespace _7属性访问修饰符
{
    internal class Program
    {
        static void Main(string[] args)
        {
            People p = new People();
            Console.WriteLine(p.a);
            Console.WriteLine(p.d);
            Console.WriteLine(p.e);
        }
    }

    public class People
    {
        public int a = 10;
        private int b = 20;
        protected int c = 30;
        protected internal int d = 30;
        internal int e = 30;

        public void F1()
        {
            // 本类中所有修饰符都可访问
            Console.WriteLine(a);
            Console.WriteLine(b);
            Console.WriteLine(c);
            Console.WriteLine(d);
            Console.WriteLine(e);
        }
    }

    // 本项目子类
    public class Man : People
    {
        public void F2()
        {
            Console.WriteLine(a);
            Console.WriteLine(c);
            Console.WriteLine(d);
            Console.WriteLine(e);
        }
    }
}

2. 跨项目测试代码(引用上方命名空间)

cs 复制代码
using System;
using _7属性访问修饰符;

namespace _8测试访问修饰符
{
    internal class Program
    {
        static void Main(string[] args)
        {
            People p = new People();
            Console.WriteLine(p.a); // public 跨项目可访问
        }
    }

    // 跨项目子类
    public class Woman : People
    {
        public void F3()
        {
            Console.WriteLine(a);
            Console.WriteLine(c);
            Console.WriteLine(d);
            // Console.WriteLine(e); internal 跨项目不可访问
        }
    }
}

六、多态:函数重载(静态多态)

1. 多态分类

  • 静态多态(编译期):函数重载、运算符重载
  • 动态多态(运行期):虚方法、抽象类、接口

2. 函数重载条件(必须全部满足)

  1. 方法名完全相同
  2. 参数个数 / 类型 / 顺序不同
  3. 仅返回值不同,不构成重载

代码示例

cs 复制代码
using System;

namespace _9多态_函数重载
{
    internal class Program
    {
        static void Main(string[] args)
        {

        }

        public static void F1()
        {
            Console.WriteLine("无参方法");
        }

        public static void F1(int a)
        {
            Console.WriteLine("int 参数");
        }

        public static void F1(string a)
        {
            Console.WriteLine("string 参数");
        }

        public static void F1(string a, int b)
        {
            Console.WriteLine("两个参数");
        }

        public static int F1(bool b)
        {
            Console.WriteLine("bool 参数");
            return 10;
        }
    }
}

七、运算符重载

规则

  1. 使用 public static operator 运算符 语法
  2. 必须为静态方法,参数至少包含一个当前类类型
  3. 常用重载:+、-、++、>、<

完整代码(盒子对象运算)

cs 复制代码
using System;

namespace _10运算符号重载
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Box b1 = new Box(10, 20, 30);
            Box b2 = new Box(30, 40, 50);

            // 重载 +
            Box b3 = b1 + b2;
            Console.WriteLine($"{b3.Length} {b3.Width} {b3.Height}");

            // 重载 -
            int b4 = b1 - b2;
            Console.WriteLine(b4);

            // 重载 ++
            Box b5 = b1++;
            Console.WriteLine(b1.Length);
            Console.WriteLine(b5.Length);

            // 重载 > <
            Console.WriteLine(b1 > b2);
            Console.WriteLine(b1 < b2);
        }
    }

    public class Box
    {
        public int Length { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }

        // 体积
        public int Volume
        {
            get { return Length * Width * Height; }
        }

        public Box() { }
        public Box(int l, int w, int h)
        {
            Length = l;
            Width = w;
            Height = h;
        }

        // 重载 +
        public static Box operator +(Box b1, Box b2)
        {
            return new Box
            {
                Length = b1.Length + b2.Length,
                Width = b1.Width + b2.Width,
                Height = b1.Height + b2.Height
            };
        }

        // 重载 -
        public static int operator -(Box b1, Box b2)
        {
            return b1.Volume - b2.Volume;
        }

        // 重载 ++
        public static Box operator ++(Box b1)
        {
            return new Box
            {
                Length = b1.Length + 1,
                Width = b1.Width + 1,
                Height = b1.Height + 1
            };
        }

        // 重载 >
        public static bool operator >(Box b1, Box b2)
        {
            return b1.Volume > b2.Volume;
        }

        // 重载 <
        public static bool operator <(Box b1, Box b2)
        {
            return b1.Volume < b2.Volume;
        }
    }
}

八、抽象类(abstract)

核心特点

  1. abstract 修饰,不能实例化,专门用于被继承
  2. 可包含:普通属性、普通方法、抽象属性 / 抽象方法
  3. 抽象方法:无方法体 {},子类必须用 override 重写实现
  4. 子类如果也是抽象类,可选择性不实现抽象成员;非抽象子类必须实现所有抽象成员

完整代码

cs 复制代码
using System;

namespace _11抽象类
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // People p = new People(); 报错:抽象类无法实例化
        }
    }

    // 抽象父类
    abstract class People
    {
        // 普通属性
        public int Age { get; set; }

        // 普通方法
        public void F2()
        {
            Console.WriteLine("普通方法");
        }

        // 抽象属性(无实现)
        public abstract string Name { get; set; }

        // 抽象方法(无方法体)
        public abstract void F1();
    }

    // 非抽象子类:必须重写所有抽象成员
    class Student : People
    {
        public override string Name { get; set; } = "学生";

        public override void F1()
        {
            Console.WriteLine("子类实现抽象方法 F1");
        }
    }
}

总结

  1. 静态成员:类共享,静态方法只能访问静态成员
  2. readonly / const:const 编译常量,readonly 运行只读,赋值位置有严格限制
  3. 继承:C# 单继承,构造函数永远先执行父类
  4. 访问修饰符:控制跨类、跨项目、子类的访问权限
  5. 静态多态:函数重载、运算符重载,依赖参数区分
  6. 抽象类:模板类,强制子类实现抽象方法,不可实例化
相关推荐
武子康1 小时前
Build-Your-Own-X 从零构建轻量级事件驱动微框架:嵌入式与物联网场景下的极简实践
人工智能·后端·物联网·ai·c#·大模型·嵌入式
xiaoshuaishuai817 小时前
C# AvaloniaUI 资源找不到报错
java·服务器·前端·windows·c#
Xin_ye1008617 小时前
C# 零基础到精通教程 - 第十八章:部署与发布——让应用上线
开发语言·c#
爱讲故事的18 小时前
操作系统第一讲复习:为什么学习操作系统,以及操作系统到底在做什么?
linux·开发语言·windows·学习·ubuntu·c#
JaydenAI19 小时前
[MAF预定义的AIContextProvider-03]ChatHistoryMemoryProvider——赋予Agent从经验中学习的能力
ai·c#·agent·memory·maf
z落落20 小时前
C# 继承:父子构造函数 + base 关键字 +五大访问修饰符(同项目+跨项目 全覆盖)
开发语言·c#
海盗123420 小时前
C#中PDF操作-QuestPDF页面设置与布局
java·pdf·c#
玩c#的小杜同学21 小时前
一周 AI 新鲜事|2026.05.25—2026.05.31
人工智能·程序人生·ai·c#·程序员创富