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

时间:2012-02-16 16:30:38

标签: c#

由于每个类都是从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
}

现在 OBJECT OF CLASS“C”是指A,B以及system.object类吗?

5 个答案:

答案 0 :(得分:6)

我花了一段时间,但我发现了。 您认为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.prototype,而Animal.prototype会引用Object.prototype。< / p>

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

答案 1 :(得分:1)

通过阅读评论,您的误解似乎是当您创建C类实例时,还有B,A或Object类的单独实例。事实并非如此。有一个对象是C类的实例,它也可以被视为B类,A类或Object类的实例(在Liskov Substitution Principle上读取)。修改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类定义的东西!所以每次在继承链中添加另一个类时,该类中定义的字段只会被添加到内存的末尾。其父类的结构。

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

答案 2 :(得分:0)

C类型的对象也可以是B,A和System.Object类型。

它将包含它继承的其他类的所有成员(公共或受保护的方法,属性和字段)。这就是为什么所有对象都有“ToString”方法 - 它们从System.Object继承它。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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);

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