base到底指向了谁

base关键字在随笔《用《叩响C#之门》复习C#基础知识 第九章 面向对象编程:继承》叙述过一些,但自己试验后,发现表述不妥,拎出来单独分析下

每个对象都有一个指向自身的引用符即this,同样,可以通过base关键字来访问基类成员。

base常用于1)在派生类对象初始化时和基类进行通信(即调用派生类构造函数前调用基类构造函数);2)访问基类的公有成员和受保护成员,私有成员不可访问;同时,base用来调用基类中已被派生类中方法重写的方法(是调用基类中的方法,不象上篇随笔中,基类应用符访问方法,结果访问到派生类中重写后的方法)。

针对第2)点分析如下:

自己分析的:base应该被看做是调用base关键字的方法所属的类型的最直接的基类型对象的引用(虽然base其实不能作为引用符来赋值)

由此可见,派生类对象生成后,实际上在堆中的低内存存储着基类的成员,相当于整个派生类对象包含着某个基类对象。(这样理解,真是把自己吓一跳,但,目前感觉是对的)base实际上是指向:内存中 调用base的方法所属类型B的最直接的基类A所包含的成员(可将此部分内存内容看做是A的对象)

1)针对基类的字段,通过base去访问托管堆中的GC堆的基类字段。

2)针对基类的方法,通过base去访问托管堆中的Loader Heap堆中的基类方法表。

真正使用时,引用符及所调用的方法,规则遵循上篇随笔《针对基类引用符指向派生类对象引起的思考》中的描述。

注意:this和base关键字都不能用于静态方法中(因为都是放在对象的方法中使用的),也就是说在Main()方法中也不可以使用。

 

以练习来说明:

using System;
using System.Collections.Generic;
namespace Test
{
    public class Animal
    {
        protected string name;
        public virtual string Name
        {
            get { return "调用自Animal的Name  " + this.name; }
            set { this.name = value; }
        }
        public virtual void DisplayName()
        {
            Console.WriteLine("Animal类传下的Display方法");
        }
        public virtual void ReturnBase()//检查各类使用base的情况
        {

            Console.WriteLine("调用Animal的ReturnBase()   ");

        }
    }
    public class Vertebrata : Animal
    {
        public override string Name//对属性Name进行了覆写
        {
            get
            {
                return "调用自Vertebrata的Name  " + this.name;
            }
            set
            {
                this.name = value;
            }
        }
        public override void DisplayName()//对方法DisplayName()进行了覆写
        {
            Console.WriteLine("Vertebrata类传下的Display方法");
        }
        public override void ReturnBase()//检查各类使用base的情况
        {
            Console.Write("调用Vertebrata的ReturnBase()   ");
            base.DisplayName();

        }
    }
    public class Mammal : Vertebrata
    {
        public override string Name
        {
            get
            {
                return "调用自Mammal的Name  " + this.name;
            }
            set
            {
                this.name = value;
            }
        }
        public override void DisplayName()
        {
            Console.WriteLine("Mammal类传下的Display方法");
        }
        public override void ReturnBase()//检查各类使用base的情况
        {  
            Console.Write("调用Mammal的ReturnBase()   ");
            base.DisplayName();

        }

    }
    public class Cat : Mammal
    {
        public override string Name
        {
            get
            {
                return "调用自Cat类的Name " + this.name;
            }
            set
            {
                this.name = value;
            }
        }
        public override void ReturnBase()//检查各类使用base的情况
        {
            Console.Write("调用Cat的ReturnBase()   ");
            base.DisplayName();
        }

    }
    public class Program
    {
        static void Main()
        {
            Animal ani1 = new Cat();
            Animal ani2 = new Mammal();
            Animal ani3 = new Vertebrata();
            Animal ani4 = new Animal();

            Vertebrata vert1 = new Cat();
            Vertebrata vert2 = new Mammal();
            Vertebrata vert3 = new Vertebrata();

            Mammal mam1 = new Cat();
            Mammal mam2 = new Mammal();

            Cat cat1 = new Cat();

            ani1.ReturnBase();
            ani2.ReturnBase();
            ani3.ReturnBase();
            ani4.ReturnBase();
            Console.WriteLine();
            vert1.ReturnBase();
            vert2.ReturnBase();
            vert3.ReturnBase();
            Console.WriteLine();
            mam1.ReturnBase();
            mam2.ReturnBase();
            Console.WriteLine();
            cat1.ReturnBase();

            


        }



    }
}

输出:

 image 

此段代码实际上是将上篇随笔的规则也体现出来了,输出左边部分为不同类型引用符访问同名函数时,访问的规则。输出右边部分为方法调用base后的结果。

显然,当引用符类型为基类A,A的派生类为B,而此时引用符指向的是B的派生类C的对象,先是找到应当访问的函数(如此函数在C中,即C中重写了A中的虚函数),当该函数中含base关键字时,base则访问此函数对应类的直接基类(B)所对应的内存中B类的成员(即可将内存中这部分内容看作为B的对象,因为C的对象可以看做包含着B的对象,B的对象包含着A的对象,统筹创建成了C的对象)。综上,如此说来,倒可以牵强地将base看做为指向基类对象的引用符了。

 

如果将上述代码中Cat类中的ReturnBase()隐藏掉,输出结果如下:

按此篇随笔的内容,应该不难分析出输出的结论了

 

image

posted on 2009-10-25 20:36  友闻语上  阅读(373)  评论(0编辑  收藏  举报