某个类的新创建对象以何种方式引用派生它的类

本文关键字:方式 引用 派生 何种 创建对象 | 更新日期: 2023-09-27 18:24:47

由于每个类都是从system.object派生的,派生的类对象是否引用其层次结构中的类?(当然,只在他们之上的类(

例如

public class A
{
//contains some attributes and methods
}
public class B: A
{
//contains some attributes and methods
}
public class C: B
{
//contains some attributes and methods
}

现在,类"C"的对象是指A,B以及system.object类吗?

某个类的新创建对象以何种方式引用派生它的类

我花了一段时间,但我想通了。您认为 C# 是一种"原型继承"语言。不是。

在原型继承语言中,如JavaScript,每个对象都有一个对其"原型对象"的引用。所以在 JavaScript 中,你可能会说:

function Dog() {}
Dog.prototype.legs = 4;
var rover = new Dog();
var spot = new Dog();
spot.legs = 3; // Poor spot!
print(rover.legs); // 4
print(spot.legs); // 3

roverspot引用Dog.prototype。当你问rover"你有多少条腿? rover说:"我不知道;让我问问我的原型"。rover引用的对象本身具有对Dog.prototype引用的对象,并且该对象具有legs属性。

当你问spot"你有几条腿?"时,spot也有它的原型,但它不需要它,因为spot已经知道它有多少条腿了。

通过更多的工作,我们可以构建一个系统,其中Dog.prototype的原型是"Animal原型对象"。然后链条将继续; rover将引用Dog.prototypeDog.prototype将引用Animal.prototypeAnimal.prototype将引用Object.prototype

C# 根本不是这样工作的。 在 JavaScript 中,对象是原型链列表的一部分,当需要查找属性时,会搜索原型链。在 C# 中,每个属性的所有信息都存储在每个实例中。在 C# 中,对象不引用其基类型的实例,也不包含其基类型的实例;相反,它继承其基类型的所有成员。(构造函数和析构函数除外。

从阅读注释来看,您的误解似乎是,当您创建类 C 的实例时,还有类 B、A 或 Object 的单独实例。 事实并非如此。 有一个对象是类 C 的实例,它也可以被视为类 B、A 或对象的实例(阅读 Liskov 替换原则(。 修改埃里克·利珀特(Eric Lippert(的类比:当狗被创造(出生(时,它是狗,哺乳动物和动物。 但只有一只狗。

考虑一下(动物,哺乳动物,狗,而不是A,B,C(:

public class Animal 
{ 
    void Breathe();
} 
public class Mammal : Animal
{ 
    void GrowHair();
} 
public class Dog
{ 
    void Bark();
} 

此继承链具有以下效果:

public class C
{
    void Breathe();
    void GrowHair();
    void Bark();
}

就字段而言,回到 A、B、C,考虑一下:

public class A            
{            
    private int _a;
}            
public class B: A            
{            
    private int _b;
}            
public class C: B            
{            
    private int _c;
}   

A 的实例在内存中的外观如何? 一些字节的开销,加上四个字节用于_a

OVERHEAD
_a : four bytes

B 的实例在内存中的外观如何? 它看起来就像 A 加上另外四个字节的实例:

OVERHEAD
_a : four bytes
_b : four bytes

C 的实例看起来像 A 的实例加上另外八个字节:

OVERHEAD
_a : four bytes
_b : four bytes
_c : four bytes

开销是多少? 毫不奇怪,这就是Object类定义的东西! 因此,每次将另一个类添加到继承链时,该类中定义的字段都会被附加到其父类的内存结构的末尾。

派生类的实例不引用其父类定义的数据;它包含由其父类定义的数据。

C 类型的对象也是 B、A 和 System.Object 的类型。

它将具有它继承的其他类的所有成员(公共或受保护的方法、属性和字段(。这就是为什么所有对象都有一个"ToString"方法的原因 - 它们从 System.Object 继承它。

是的。默认情况下,所有类都隐式引用 system.object 类。

不完全是,但它比其他任何东西都更语义化。

C 的对象引用名为 C 的类定义的实例。 但是,它可能被类型转换为类型A,B或普通的旧System.Object的对象。

C 和 A/B/System.Object 之间没有"引用"。 它更像是将所有这些类定义合并到一个统一的"C"中。

这意味着您可以执行以下操作:

function void DoSomething(A input) { 
  // do something as A
}
C myObj = new C();
DoSomething(myObj);

在上述情况下,C 将在 DoSomething 调用中被类型强制转换为类型 A 的对象。

您还可以执行以下操作:

public class A {
  public String MyValue { get; set; }
}
public class B : A{
  public String AnotherValue { get; set; }
}
public class C : B {
  public void DoSomething() {
    MyValue = "Hello";
    AnotherValue = "World";
  }
  public String Output() {
    return String.Format("{0} {1}", MyValue, AnotherValue);
  }
}
C myObj = new C();
C.DoSomething();
String message = C.Output();
// value of message will be "Hello World"

现在反之则不然。 您不能执行以下操作:

function void DoSomething(C input) { 
  // do something as C
}
A myObj = new A();
DoSomething(myObj);

在这种情况下,您将遇到编译器错误。