使用 C# 学习面向对象编程:第 4 部分

news2025/1/14 18:26:10

C# 构造函数

第 1 部分仅介绍了类构造函数的基础知识。 在本课中,我们将详细讨论各种类型的构造函数。

属性类型

  • 默认构造函数
  • 构造函数重载
  • 私有构造函数
  • 构造函数链
  • 静态构造函数
  • 析构函数

请注意构造函数的一些基本概念,并确保你的理解非常清楚,否则你无法理解 OOP(构造函数)。

  1. 构造函数的名称与类名相同。
  2. 构造函数的目的是为了初始化成员变量。
  3. 创建对象时会自动调用构造函数。
  4. 构造函数没有任何返回类型,甚至没有 void。
  5. 如果我们希望自动执行某些代码,那么我们想要执行的代码必须放在构造函数中。
  6. 我们不能明确调用构造函数。

C# 构造函数的一般形式如下。

modifier constructor_name(parameters)
{
    // constructor body
}

修饰符可以是 private、public、protected 或 internal。构造函数的名称必须是其定义所属类的名称。构造函数可以接受零个或多个参数。零个参数(即无参数)的构造函数称为默认构造函数。请记住,构造函数没有返回类型。

默认构造函数

无参数的构造函数称为默认构造函数。请记住,构造函数没有返回类型。默认构造函数只是调用直接基类的无参数构造函数。

例子

using System;

namespace DefaultConstructors
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建 car 类的一个实例 sportscar,调用默认构造函数
            car sportscar = new car();

            // 打印 sportscar 的 model_Id 属性值
            Console.WriteLine("Car Model is :{0} ", sportscar.model_Id);

            // 打印 sportscar 的 Maker_Name 属性值
            Console.WriteLine("Car Name is :{0}", sportscar.Maker_Name);

            // 等待用户按下任意键继续执行程序
            Console.ReadKey();
        }

        // 定义 car 类
        class car
        {
            // 私有字段 model,表示车型
            private int model = -1;

            // 私有字段 maker,表示制造商
            private string maker = string.Empty;

            // 默认构造函数
            public car()
            {
                // 默认构造函数的主体是空的,可以添加初始化逻辑
            }

            // 公共只读属性 model_Id,用于获取 model 字段的值
            public int model_Id
            {
                get 
                {
                    return model;
                }
            }

            // 公共只读属性 Maker_Name,用于获取 maker 字段的值
            public string Maker_Name
            {
                get
                {
                    return maker;
                }
            }
        }
    }
}

输出


在这个简单的例子中,我们有一个无参数或零参数的构造函数,它是类的默认构造函数。上述示例的输出是空成员变量。

请注意另外一点;如果我们从示例 1 中删除以下代码,则输出是相同的。

public car()
{
   //Default Constructor
}

这意味着如果我们没有定义类的构造函数,系统将调用默认构造函数。

构造函数重载

首先,我们来讨论一下构造函数重载的目的;对前面的主题有清晰的理解非常重要。在设计 OOP 模型时存在许多复杂的情况,我们需要为类的不同目的初始化一组不同的成员变量。所以我们需要使用构造函数重载。构造函数重载的定义是。

和成员函数一样,构造函数也可以在类中重载。重载的构造函数必须在参数数量和/或参数类型和/或参数顺序上有所不同。

例子

using System;

namespace ConstructorsOverloading
{
    class Program
    {
        static void Main(string[] args)
        {
            // 使用无参数构造函数创建 car 类的一个实例
            car sportscar1 = new car();

            // 使用包含两个参数(model 和 maker)的构造函数创建 car 类的一个实例
            car sportscar2 = new car(2013, "mercedes");

            // 使用包含两个参数(maker 和 Enginetype)的构造函数创建 car 类的一个实例
            car sportscar3 = new car("mercedes", 7.8);

            // 输出使用无参数构造函数创建的 sportscar1 的属性值
            Console.WriteLine("Constructor without arguments");
            Console.WriteLine("Car Model is :{0} ", sportscar1.model_Id);
            Console.WriteLine("Car Name is :{0}", sportscar1.Maker_Name);
            Console.WriteLine("Car Engine Power is :{0}", sportscar1.Engine);

            // 输出使用包含两个参数的构造函数创建的 sportscar2 的属性值
            Console.WriteLine("\nConstructor with two arguments");
            Console.WriteLine("Car Model is :{0} ", sportscar2.model_Id);
            Console.WriteLine("Car Name is :{0}", sportscar2.Maker_Name);
            Console.WriteLine("Car Engine Power is :{0}", sportscar2.Engine);

            // 输出使用包含两个参数的构造函数创建的 sportscar3 的属性值
            Console.WriteLine("\nConstructor with two arguments");
            Console.WriteLine("Car Model is :{0} ", sportscar3.model_Id);
            Console.WriteLine("Car Name is :{0} ", sportscar3.Maker_Name);
            Console.WriteLine("Car Engine Power is :{0}", sportscar3.Engine);

            // 等待用户按下任意键继续执行程序
            Console.ReadKey();
        }

        // 定义 car 类
        class car
        {
            // 私有字段,表示车型
            private int model = -1;

            // 私有字段,表示制造商
            private string maker = string.Empty;

            // 私有字段,表示发动机类型
            private double Enginetype = 0.0;

            // 无参数的默认构造函数
            public car()
            {
                // 默认构造函数的主体是空的,可以添加初始化逻辑
            }

            // 包含两个参数(model 和 maker)的构造函数
            public car(int _model, string _maker)
            {
                model = _model;
                maker = _maker;
            }

            // 包含两个参数(maker 和 Enginetype)的构造函数
            public car(string _maker, double _power)
            {
                maker = _maker;
                Enginetype = _power;
            }

            // 公共属性,用于获取和设置 model 字段的值
            public int model_Id
            {
                get
                {
                    return model;
                }
                set
                {
                    model = value;
                }
            }

            // 公共属性,用于获取和设置 maker 字段的值
            public string Maker_Name
            {
                get
                {
                    return maker;
                }
                set
                {
                    maker = value;
                }
            }

            // 公共属性,用于获取和设置 Enginetype 字段的值
            public double Engine
            {
                get
                {
                    return Enginetype;
                }
                set
                {
                    Enginetype = value;
                }
            }
        }
    }
}

输出


亲爱的读者,请注意,在这个例子中,我们使用三个不同的对象重载了构造函数,它们是sportscar1、sportscar2 和 sportscar3。

我们注意到

  • sportscar1 没有参数(默认构造函数超出了主题范围)。因此该成员变量具有在初始化时分配的默认值。
  • sportscar2 有两个参数,分别用值 2013 和 Mercedes 初始化成员变量 model 和 name,但没有初始化 Enginetype 变量,因此它具有默认值零。
  • sportscar3 有两个参数,分别用值 Mercedes 和 7.8 初始化成员变量 name 和 Enginetype,但不初始化 model 变量,因此它具有默认值 -1。

私有构造函数

亲爱的读者,我们知道,私有访问修饰符有点特殊。我们既不能创建类的对象,也不能仅使用私有构造函数来继承类。但是,是的,我们可以在类中拥有一组公共构造函数以及私有构造函数,并且公共构造函数可以通过构造函数链从类内部访问私有构造函数。私有构造函数通常用于仅包含静态成员的类中。

using System;

namespace PrivateConstructors
{
    class Program
    {
        static void Main(string[] args)
        {
            // 使用包含 model 参数的构造函数创建 car 类的一个实例
            car sportscar = new car(2013);
            Console.Read();
        }

        class car
        {
            // 公共字段,表示汽车名称
            public string carname;

            // 私有的默认构造函数
            private car()
            {
                // 初始化 carname 字段
                carname = "lamborghini";
            }

            // 公共的构造函数,包含一个 int 型的 model 参数
            // 该构造函数通过 :this() 调用私有的默认构造函数
            public car(int model) : this()
            {
                // 打印车型年份
                Console.WriteLine("Model Year:{0}", model);

                // 打印制造商名称
                Console.WriteLine("Maker Name:{0}", carname);
            }
        }
    }
}

这是一个非常简单的私有构造函数的例子,其中我们使用公共构造函数来调用私有构造函数。

构造函数链

亲爱的读者,当一个构造函数调用同一个类或该类的基类中的另一个构造函数时,这被称为构造函数链。这是避免代码重复的非常有用的技术。

using System;

namespace Constructorchaining
{
    class Program
    {
        static void Main(string[] args)
        {
            // 使用包含 engine 参数的构造函数创建 car 类的一个实例
            car sportscar = new car(7.8);
            Console.Read();
        }

        class car
        {
            // 公共字段,表示汽车名称
            public string carname;

            // 公共字段,表示车型年份
            public int model;

            // 公共字段,表示发动机类型
            public double engine;

            // 包含一个 carname 参数的构造函数
            public car(string _carname)
            {
                carname = _carname;
            }

            // 包含一个 model 参数的构造函数,并调用包含 carname 参数的构造函数
            public car(int _model) : this("lamborghini")
            {
                model = _model;
            }

            // 包含一个 engine 参数的构造函数,并调用包含 model 参数的构造函数
            public car(double _engine) : this(2013)
            {
                engine = _engine;
                
                // 打印车型年份
                Console.WriteLine("Model Year:{0}", model);
                
                // 打印制造商名称
                Console.WriteLine("Maker Name:{0}", carname);
                
                // 打印发动机类型
                Console.WriteLine("Engine Type:{0}", engine);
            }
        }
    }
}

在前面的例子中,我们创建了三个不同的类,它们都具有相同的名称 car 和不同的参数类型,每个类都链接前一个类来调用另一个构造函数。

静态构造函数

静态构造函数是一种特殊类型,不采用访问修饰符,也不具有参数。在创建第一个实例或引用任何静态成员之前,会自动调用它以初始化类。静态构造函数不会被直接调用。用户无法控制静态构造函数的执行。

using System;

namespace staticconstructors
{
    class Program
    {
        // 定义 car 类
        public class car
        {
            // 静态构造函数
            static car()
            {
                // 打印静态信息,静态构造函数在类第一次被使用前自动调用,并且只调用一次
                System.Console.WriteLine(@"Lamborghini is the best sports car owned by Audi AG 1998 (its static info)");
            }

            // 静态方法 Drive
            public static void Drive()
            {
                // 打印稳定公司信息
                System.Console.WriteLine("Audi is the stable company");
            }
        }

        // 主程序入口点
        static void Main()
        {
            // 调用 car 类的静态方法 Drive
            car.Drive();

            // 再次调用 car 类的静态方法 Drive
            car.Drive();

            // 等待用户按下任意键继续执行程序
            Console.ReadKey();
        }
    }
}

输出


注意,静态构造函数在第一次加载类时被调用。当我们再次调用“car.Drive”时,它不会调用静态构造函数。

析构函数

亲爱的读者,当我们使用 OOP 并在系统内存中创建对象时,需要从系统内存中清除不需要的对象。.NET 框架内置了垃圾收集功能,用于释放未使用对象占用的内存。析构函数是一个与类名同名但以字符 ~ 开头的函数。析构函数不能有任何修饰符 private、public 等。

例子

class car
{
    // 公共构造函数
    public car()
    {
        // 构造函数,在创建对象实例时调用
        // 可以在这里进行对象的初始化操作
        // 比如分配资源,设置初始状态等
    }

    // 析构函数
    ~car()
    {
        // 析构函数,在对象被垃圾回收时调用
        // 可以在这里进行对象的清理操作
        // 比如释放资源,关闭文件,断开网络连接等
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1810757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 分片上传、断点续传、大文件上传、秒传,应有尽有

文件上传是一个老生常谈的话题了,在文件相对比较小的情况下,可以直接把文件转化为字节流上传到服务器,但在文件比较大的情况下,用普通的方式进行上传,这可不是一个好的办法,毕竟很少有人会忍受,…

怎么隐藏文件夹?4个方法保护文件!

“我在使用电脑时,想将一个比较重要的文件夹隐藏,但是不知道应该怎么操作,请大家给我出出主意。” 在数字化时代,我们的电脑和手机中存储着大量个人信息和敏感数据。其中,一些文件夹可能包含了不愿被他人轻易发现的私密…

【全篇】C语言从入门到入土

【全篇】C语言从入门到入土 文章目录 【全篇】C语言从入门到入土第一章 前言如何去学习,学习方法论 第二章 初识1.代码编译工具2.c程序的基础框架3.数据的表现形式变量1.要先定义后使用(变量名的定义是由自己决定的,一般倾向于顾文生义&#…

Bankless:为什么 AI 需要 Crypto 的技术?

原文标题:《Why AI Needs Crypto’s Values》 撰文:Arjun Chand,Bankless 编译:Chris,Techub News 原文来自香港Web3媒体:Techub News 人工智能革命的梦想一直是一把双刃剑。 释放人工智能的潜力可以解…

MySQL高性能(MySQL锁)

MySQL性能系列 MySQL锁 前言1. 死锁机制2. 思维导图与锁划分介绍3. 粒度划分锁3.1. 全局锁3.2. 页级锁(Page-level locking)3.3. 表级锁(Tables-level lock)○ 共享锁(表级)○ 排他锁(表级&…

JS 实现动态规划

function getPaths(m, n) {// m * n 二维数组&#xff0c;模拟网格const map new Array(m)for (let i 0; i < m; i) {map[i] new Array(n)}// 如果只走第一行&#xff0c;就只有一条路径。所以第一行所有 item 都填充 1map[0].fill(1)// 如果只走第一列&#xff0c;也只有…

vulnhub靶场:PWNOS: 2.0 (PRE-RELEASE)多种渗透方法

本文介绍靶机PWNOS: 2.0 的渗透方法&#xff0c;由于靶机系统比较老&#xff0c;尝试了几种不同的角度获得shell和提权。 1 环境搭建 根据提示信息&#xff0c;需要将网段设置为10.10.10.0/24&#xff0c;靶机ip为10.10.10.100。可以配置仅主机模式或NAT模式网卡&#xff0c;…

王学岗鸿蒙开发(北向)——————(十三)音乐播放器

AudioRenderer适合录音 AVPlayer:简单的本地单曲播放 MP3文件放置的地方 import media from ohos.multimedia.media import common from ohos.app.ability.common; Entry Component struct Index {//第1步&#xff1a;avPlayer:media.AVPlayer nullasync onPageShow(){//第…

Parallels Desktop 虚拟机必备软件有哪些 虚拟机软件有什么作用和用途

随着苹果M系列芯片电脑的推出&#xff0c;虚拟机的使用变得越来越流行。不同于苹果以往的Intel处理器电脑&#xff0c;其M系列芯片电脑无法安装双系统。如果要使用非macOS系统&#xff0c;可以通过创建虚拟机系统的方式实现。那么&#xff0c;虚拟机软件有什么作用和用途&#…

AXI Quad SPI IP核配置详解

AXI Quad SPI IP核&#xff08;Quad Serial Peripheral Interface&#xff09;是一个提供串行接口连接SPI从设备的解决方案&#xff0c;它支持Standard&#xff08;单线路&#xff09;、Dual&#xff08;双线路&#xff09;、Quad&#xff08;四线路&#xff09;模式&#xff0…

ARM32开发--外部中断EXTI

知不足而奋进 望远山而前行 目录 文章目录 前言 目标 内容 外部中断概念 中断触发机制 中断触发源 硬件外部中断 需求 开发流程 关心的内容 完整代码 软件外部中断 需求 开发流程 关心的内容 完整代码 中断消抖处理 系统计数模块 自定义计数器 systick完成…

LCD屏的价格和显示区的尺寸有关

LCD屏的价格和显示区的尺寸有关&#xff0c;和外尺寸无关。 下面通过12864点阵屏&#xff0c;对不同尺寸的屏&#xff0c;进行价格比较&#xff0c;就可以发现&#xff1a;LCD屏的价格和显示区的尺寸有关&#xff1b; 同点阵的屏&#xff0c;显示区域太小&#xff0c;显示12*1…

AMD在行动:揭示应用程序跟踪和性能分析的力量

AMD in Action: Unveiling the Power of Application Tracing and Profiling — ROCm Blogs 导言 Rocprof是一款强大的工具&#xff0c;设计用于分析和优化基于AMD ROCm平台上运行的HIP程序的性能&#xff0c;帮助开发者找出并解决性能瓶颈。Rocprof提供了多种性能数据&#x…

8.11 矢量图层线要素单一符号使用六(光栅线)

文章目录 前言光栅线&#xff08;Raster Line&#xff09;QGis设置线符号为光栅线&#xff08;Raster Line&#xff09;二次开发代码实现光栅线&#xff08;Raster Line&#xff09; 总结 前言 本章介绍矢量图层线要素单一符号中光栅线&#xff08;Raster Line&#xff09;的使…

【三维重建】增量SFM系统

在学习完鲁鹏老师的三维重建基础后&#xff0c;打算用C代码复现一下增量SFM系统&#xff08;https://github.com/ldx-star/SFM&#xff09;。 本项目的最终目标就是通过相机拍摄的多视角视图获取三维点云。由于资金有效&#xff0c;博主使用的是相机是小米12。 先来看一下最终…

Linux 安装ab测试工具

yum -y install httpd-tools ab -help #10个并发连接&#xff0c;100个请求 ab -n 200 -c 100 http://www.baidu.com/

算法之分治

分而治之 分治法所能解决的问题一般具有以下几个特征&#xff1a; 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的子问题&#xff0c;即该问题具有最优子结构性质 3) 利用该问题分解出的子问题的解可以合并为该问题的解 4) 该问题所分…

动态内存管理学不懂,小代老师带你深入理解动态内存管理(下卷)

动态内存管理学不懂&#xff0c;小代老师带你深入理解动态内存管理&#xff08;下卷 柔性数组6.1 柔性数组的特点&#xff1a;6.2 柔性数组的使用 7. 总结C/C中程序内存区域划分 柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#x…

探索C++ STL的设计方式:将算法与数据结构分离

STL的设计 一、简介二、STL容器三、C数组四、用户定义的集合4.1、使用标准集合的typedef4.2、重用标准迭代器4.3、实现自己的迭代器 五、总结 一、简介 本文介绍STL的设计方式&#xff0c;以及如何设计自己的组件&#xff0c;使其能够充分利用STL的功能。 STL的设计旨在将算法…

Golang | Leetcode Golang题解之第135题分发糖果

题目&#xff1a; 题解&#xff1a; func candy(ratings []int) int {n : len(ratings)ans, inc, dec, pre : 1, 1, 0, 1for i : 1; i < n; i {if ratings[i] > ratings[i-1] {dec 0if ratings[i] ratings[i-1] {pre 1} else {pre}ans preinc pre} else {decif dec…