【发布时间】:2011-08-01 21:17:51
【问题描述】:
为什么可以在 C# 中为抽象类编写构造函数?
据我所知,我们不能实例化一个抽象类。那它有什么用呢?
你不能实例化这个类,对吧?
【问题讨论】:
标签: c# constructor abstract-class
为什么可以在 C# 中为抽象类编写构造函数?
据我所知,我们不能实例化一个抽象类。那它有什么用呢?
你不能实例化这个类,对吧?
【问题讨论】:
标签: c# constructor abstract-class
因为您可能希望在抽象类中实例化数据的标准方式。这样,您就可以让从该类继承的类调用基构造函数。
public abstract class A{
private string data;
protected A(string myString){
data = myString;
}
}
public class B : A {
B(string myString) : base(myString){}
}
【讨论】:
您可以在实现所有方法后实例化它。然后会调用构造函数。
【讨论】:
这是一种强制执行抽象类的一组不变量的方法。也就是说,无论子类做什么,您都希望确保基类的某些事情总是正确的......示例:
abstract class Foo
{
public DateTime TimeCreated {get; private set;}
protected Foo()
{
this.TimeCreated = DateTime.Now;
}
}
abstract class Bar : Foo
{
public Bar() : base() //Bar's constructor's must call Foo's parameterless constructor.
{ }
}
不要将构造函数视为new 运算符的对偶。构造函数的唯一目的是确保您在开始使用之前拥有处于有效状态的对象。恰好我们通常通过new运算符调用它。
【讨论】:
base()。它将被自动调用,因为那是无参数构造函数。这意味着你的构造函数等价于public Bar() {}。
它可以强制执行抽象类的所有实现或您在抽象类上实现的任何方法所需的一些初始化逻辑(并非抽象类上的所有方法都必须是抽象的,有些可以实现)。
从抽象基类继承的任何类都必须调用基构造函数。
【讨论】:
据我所知,我们无法实例化抽象类
你的错误就在那里。 当然你可以实例化一个抽象类。
abstract class Animal {}
class Giraffe : Animal {}
...
Animal animal = new Giraffe();
那里有一个 Animal 的实例。您通过创建一个派生自抽象类的具体类并实例化它来实例化一个抽象类。请记住,派生具体类的实例也是其抽象基类的实例。 即使 Animal 是抽象的,Giraffe 的实例也是 Animal 的实例。
鉴于您可以实例化一个抽象类,它需要像任何其他类一样具有构造函数,以确保满足其不变量。
现在,static 类是您实际上无法实例化的类,您会注意到在静态类中创建实例构造函数是不合法的。
【讨论】:
Foo 是一个可继承的具体类型,而DerivedFoo:Foo,你会用什么术语来描述一个堆对象实例,它将其类型报告为Foo,如不同于DerivedFoo?我自己的倾向是使用短语“T 的实例”来指代 exact 类型为 T 的东西。否则我会倾向于说“T 或某种派生”之类的话, “T 的一些派生”、“T 的一些实现”或“满足 T 的东西”取决于 T 是具体类、抽象类、接口还是约束。
我也想在抽象的表面上发光 所有答案几乎涵盖了所有内容。还是我的 2 美分
抽象类是普通类,有一些例外
【讨论】:
在可继承的具体类Thing 中定义具有公共或内部存储类的构造函数有效地定义了两种方法:
作用于this的方法(我称之为InitializeThing)没有返回值,只能从Thing的CreateThing和InitializeThing方法调用,和子类的InitializeXXX 方法。
一个方法(我称之为CreateThing),它返回一个构造函数指定类型的对象,本质上表现为:
Thing CreateThing(int whatever)
{
Thing result = AllocateObject<Thing>();
Thing.initializeThing(whatever);
}
抽象类有效地创建了仅第一种形式的方法。从概念上讲,上面描述的两个“方法”没有理由需要具有相同的访问说明符。然而,在实践中,没有办法以不同的方式指定它们的可访问性。请注意,就实际实现而言,至少在 .NET 中,CreateThing 并没有真正实现为可调用方法,而是表示插入到 newThing = new Thing(23); 语句中的代码序列。
【讨论】:
通常构造函数涉及初始化正在创建的对象的成员。在继承的概念中,通常继承层次结构中的每个类构造函数都负责实例化自己的成员变量。这是有道理的,因为必须在定义变量的地方进行实例化。
由于抽象类不是完全抽象的(不像接口),它是抽象和具体成员的混合,非抽象的成员需要初始化,这是在抽象类的构造函数中完成的,有必要在抽象类中有构造函数。当然抽象类的构造函数只能从派生类的构造函数中调用。
【讨论】:
抽象类可以有成员变量需要初始化,所以可以在抽象类构造函数中初始化,在派生类对象初始化时调用该构造函数。
【讨论】:
有以下两个重要特性阻止继承抽象类
抽象类必须有抽象方法,否则不是抽象类
抽象类必须由派生类继承,所以如果一个类被其他类继承而不是用来创建该类的对象
【讨论】:
来自https://msdn.microsoft.com/en-us/library/ms182126.aspx
抽象类型的构造函数只能由派生类型调用。因为公共构造函数创建类型的实例,而您不能创建抽象类型的实例,所以具有公共构造函数的抽象类型设计不正确。
由于只有派生类可以使用抽象类构造函数,因此如果需要,必须将抽象类构造函数声明为protected。
但是,当在抽象类中声明公共构造函数时,所述 VS 编译器不会抱怨(使用默认规则),但它不允许创建新实例。
【讨论】:
你完全正确。我们无法实例化抽象类,因为抽象方法没有任何主体,即抽象方法无法实现。但是可能有一些场景需要初始化基类的一些变量。 您可以按照@Rodrick 的建议使用 base 关键字来做到这一点。在这种情况下,我们需要在抽象类中使用构造函数。
【讨论】:
关于抽象类的要点
【讨论】:
添加到上面的答案和例子。
是的,一个抽象类可以有一个构造函数,即使一个抽象类不能被实例化。将解释一个抽象类构造函数 c# 代码示例。但是,下一个问题也可能出现,好像我们不能实例化(使用new构造对象)抽象类,那么构造函数在抽象类中是什么,或者为什么我们要在抽象类中使用构造函数?
请注意,当我们创建派生类的对象时,会隐式调用抽象基类的构造函数,即使我们无法实例化抽象类。比如在程序中,如果我们创建一个派生类的对象,那么抽象基类的构造函数也会被调用。
这也是例子之一
示例
abstract class A
{
protected A() {Console.WriteLine("Abstract class constructor"); }
}
//Derived class
class B : A
{
public B() {Console.WriteLine("Derived class constructor"); }
}
class Program
{
static void Main(string[] args)
{
B obj = new B();
}
}
输出将是
Abstract class constructor
Derived class constructor
【讨论】: