构造函数的作用

本文详细解析了C#中构造函数的作用及使用方法,特别是默认构造函数和空参数构造函数的重要性,并通过具体示例展示了如何在类继承中正确使用构造函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造函数主要用来初始化对象。它又分为静态(static)和实例(instance)构造函数两种类别。大家应该都了解如果来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性。实际上,我说错了。正确的说法是:以及在类中保留空参数构造函数的重要性。

我们来写一个类A,代码如下:

public class A

{

   public int Number;       //数字

   public string Word;       //文本

}

//Test类中实例化

public class Test

{

    static void Main()

{

       A a = new A(); //实例化,A()即为类A的默认构造函数

     Console.WriteLine(“Number = {0}"nWord = {1}”,a.Number,a.Word);

       Console.read();

}

}

输出的结果是:

Number = 0

Word =

在上列示例中,我们并没有在A类中明确的写出构造函数,当我们没有提供任何构造函数时,C#自动为类提供了一个默认构造函数,其格式为:

public A()

{

   //空白的方法体

}

这个默认构造函数看起来似乎根本没什么作用,没有接收任何输入参数,方法体也是个空的。那么它真的是无所事事,可有可无的一个东西吗?我们回想下前面所讲的构造函数的主要作用,对,它主要用来初始化对象。看下输出结果,int类型的Number被初始化为默认值0string类型的Word被初始化为默认值空白字符,这些工作都是由看似没起作用的默认构造函数所完成的。

很快,A类的设计让我们并不满意,我们加强了它的能力,自己提供了构造函数:

public class A

{

    public int Number;     

    public string Word;     

    public A(int number,string word)

{

   Number=number;    //标记1

   Word=word;       //标记2

}

}

//Test类也重新设计

public class Test

{

static void Main()

{

        A a = new A(100,”一百”); //调用了新的带参数构造函数

      Console.WriteLine(“Number = {0}"nWord = {1}”,a.Number,a.Word);

        Console.read();

}

}

输出结果:

Number = 100

Word = 一百

运行很顺利,结果正确。当我们提供了构造函数时,C#认为我们应该是意识到、并且有能力来做好类的初始化工作,于是它将默认的构造函数撤销,将控制权交到了我们手里。我们自己的构造函数能胜任默认构造函数的工作吗?带着怀疑,我们做个尝试,将类A构造函数的方法体清除,即注释掉标记12行,重新运行,输出的结果是:

Number =0

Word =

这个结果和调用默认构造函数的结果是一样的,这证明我们自己提供的构造函数能担当默认构造函数的工作。

不久以后,业务进一步扩展,我们要新构一个类,这个类继承自类A,我们把它称为类B

public class A

{

    public int Number;     

    public string Word;     

    public A(int number,string word)

{

   Number=number;  

   Word=word;    

}

}

public class B:A

{

    public string Name;   //增加一个成员

    public B(int number,string word)

{

   Number = number;

   Word = word;

}

}

//修改Test

public class Test

{

   static void Main()

{

       B b = new B(100,”一百”);

       Console.WriteLine(“Number = {0}"nWord = {1}”,b.Number,b.Word);

       Console.Read();

    }

}

运行后出错,错误信息是:“A”方法没有采用“0”个参数的重载。为什么会这样呢?看起来我们并没有什么错误呀。A类提供了构造函数,B类也提供了构造函数。你满腹委屈,含泪望着比尔盖茨。老比怒目圆睁,啪的给你一巴掌:“A类还没构造好,你让我怎么给你构造B类!”。A类?构造?A类还要构造吗?你莫名奇妙了。

事实上,B类要完成构造,必须先完成A类的构造。当我们采用:

public B(int number,string word)

来构造B类时,由于没有明确指明继承的构造方法,C #默认我们继承自默认构造函数。

public B(int number,string word)base()

采用这条构造函数时,C# 先调用类A的默认构造函数base()完成基类的构造,然后调用B类的构造函数完成针对B类构造的剩余工作。尝试修改上面的相应代码段为:

//在类A中添加一个空参构造函数

public class A

{

     ……

     public A()

     {

         Number =1;

         Word=”空参构造”;

     }

     …….

}

//将类B构造函数改为继承A类空参构造

public B(int number,string word):base()

实际上,我是多此一举了,public B(……):base()public B(……)是一样的,未显式指明构造函数的继承体时,C#就默认为base()

输出结果

Number=100

Word = 一百

注意看我们给A类添加的空参构造函数,我们在方法体内给Number赋值1,给Word赋值“空参构造”。然而从输出结果看,这些赋值都被覆盖了。这就说明,base()在前,而后才是public B(…..)

回头来看我们那个错误的例子。遗憾的是,我们在类A中自己提供了构造函数,这导致A类的默认构造函数消失了,当B类从A类继承默认构造函数时,找不到入口了,这就导致了如上的错误。如果要避免错误,有两种方法:1、在A类中添加一个无参数的构造函数。2B类构造函数显式继承A类的构造函数。

事情已经解释的很清楚了,不过也许还有个小问题,就是:在B类中,我们提供了一个和A类构造函数结构相同的构造函数,为什么C#不能自动识别,自动继承呢?

道理很简单,C#不能靠猜测来判断我们提供的参数究竟是要用作初始化基类还是继承类。还是来看一个例子:

public class A

{

   public int Number;

   public string Word;

    public A(int number,string word)

    {

        Number = number;

        Word = word;

    }

}

public class B:A

{

    public string Name;

    public B(int number,string word,string name):base(number,word)

    {

        Number = number;

        Word = word;

        Name = name;

    }

}

public class Test

{

    static void Main()

    {

        B b = new B(100,”一百”,”初始化B的参数”);

        Console.WriteLine(“Number = {0}"nWord = {1}"nName = {2}”,

              b.Number,b.Word,b.Name);

        Console.Read();

}

}

输出结果是:

Number = 100

Word = 一百

Name = 初始化B的参数

注意在B类的构造函数中,我们提供了三个参数,其中前两个用于初始化A类中的成员,第三个用于初始化B类的成员。虽然父类构造函数与子类构造函数的参数数量不一样,然而由于我们明确的指定了继承的关系,它们很好的完成了工作。

### C#构造函数的功能与作用C# 编程语言中,构造函数是一种特殊的方法,其主要功能是在创建对象时初始化该对象的状态。以下是关于 C# 构造函数的主要功能和作用: #### 1. 初始化对象状态 构造函数用于为新创建的对象分配初始值。这确保了对象的数据成员在其生命周期内始终拥有合理的默认值或用户指定的值[^1]。 ```csharp public class Person { public string Name; public int Age; // 默认构造函数 public Person() { Name = "Unknown"; Age = 0; } // 带参数的构造函数 public Person(string name, int age) { Name = name; Age = age; } } ``` 在此示例中,`Person` 类提供了两种构造函数:一种是没有参数的默认构造函数,另一种是可以接受 `name` 和 `age` 参数的带参构造函数。这两种构造函数分别负责设置不同的初始值[^5]。 --- #### 2. 支持重载以提供灵活性 C# 允许多个同名但签名不同的构造函数共存于同一个类中,这种特性称为 **构造函数重载**。通过这种方式,开发者可以根据实际需求选择适合的构造函数来初始化对象[^2]。 ```csharp public class Rectangle { public double Length; public double Width; // 不带参数的构造函数 public Rectangle() { Length = 1.0; Width = 1.0; } // 带参数的构造函数 public Rectangle(double length, double width) { Length = length; Width = width; } } // 使用无参构造函数 Rectangle r1 = new Rectangle(); // 使用有参构造函数 Rectangle r2 = new Rectangle(5.0, 3.0); ``` 在这个例子中,`Rectangle` 类支持两种构造方式:一是使用默认大小 (1x1),二是允许用户自定义矩形尺寸[^4]。 --- #### 3. 自动调用机制 每当使用 `new` 关键字实例化一个类时,都会自动调用相应的构造函数。这意味着开发人员无需显式调用来完成对象的初始化工作[^2]。 例如: ```csharp MyClass obj = new MyClass(); // 调用了默认构造函数 MyClass objWithParams = new MyClass(10, "example"); // 调用了带参构造函数 ``` 如果没有显式声明任何构造函数C# 编译器会隐式地为类生成一个不带参数的默认构造函数。然而,一旦手动定义了一个构造函数,编译器将不再提供默认版本。 --- #### 4. 链接多个构造函数 为了减少重复代码并提高可维护性,可以通过 `this` 关键字在一个构造函数内部调用另一个构造函数。这种方法被称为 **构造函数链式调用**[^5]。 ```csharp public class Vehicle { public string Model; public int Year; // 主构造函数 public Vehicle(string model, int year) { Model = model; Year = year; } // 辅助构造函数,调用主构造函数 public Vehicle() : this("Unspecified", 0) { } } ``` 在这里,辅助构造函数利用 `this("Unspecified", 0)` 将控制权传递给了主构造函数,从而实现了共享逻辑的目的。 --- #### 5. 提高程序的安全性和可靠性 由于构造函数会在每次创建对象时运行,它可以强制执行某些必要的验证操作或者设定特定条件下的约束规则[^3]。 ```csharp public class Account { private decimal balance; public Account(decimal initialBalance) { if (initialBalance < 0) throw new ArgumentException("Initial balance cannot be negative."); balance = initialBalance; } } ``` 此片段展示了如何防止账户余额被非法赋值的情况发生——即不允许负数作为起始金额。 --- ### 总结 综上所述,C# 中的构造函数不仅简化了对象初始化的过程,还增强了应用程序的整体健壮性以及易读性。合理设计构造函数有助于构建更加清晰、高效且易于扩展的软件架构。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值