某个类的新创建对象以何种方式引用派生它的类
本文关键字:方式 引用 派生 何种 创建对象 | 更新日期: 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
rover
和spot
都引用了Dog.prototype
。当你问rover
"你有多少条腿? rover
说:"我不知道;让我问问我的原型"。rover
引用的对象本身具有对Dog.prototype
引用的对象,并且该对象具有legs
属性。
当你问spot
"你有几条腿?"时,spot
也有它的原型,但它不需要它,因为spot
已经知道它有多少条腿了。
通过更多的工作,我们可以构建一个系统,其中Dog.prototype
的原型是"Animal
原型对象"。然后链条将继续; rover
将引用Dog.prototype
,Dog.prototype
将引用Animal.prototype
,Animal.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);
在这种情况下,您将遇到编译器错误。