【C#复习知识点2】 类、继承

——类

访问权限

public:所有类都可以访问,包括其他程序集
private:只有该类自己可以访问。
protected:只有继承该类的派生类可以访问,包括其他程序集的派生类。
internal:程序集内,都可以访问。
protected internal:程序集内,都可以访问,并且其他程序集的派生类也可以访问。

类的访问权限

类只有public和internal两种访问权限修饰符,internal只允许程序集内可见。

静态字段和静态函数

静态字段和静态函数都通过类名调用,并且静态函数中无法访问实例成员,只能访问静态成员。

常量

类中字段常量和静态字段类似,都可以在类不实例化的情况,通过类型调用。不过与静态字段不同的是,常量没有自己的存储位置,在编译时被编译器替换。并且常量不允许设置为static。

属性

属性属于函数成员。
属性的get和set访问器不可以显示使用,只能隐示使用。




属性的另个访问器必须有一个,否则会报错。
属性也可以声明为静态,表示静态的函数成员,和静态方法的用法基本一样。

构造函数

构造函数用来初始化实例的状态,如果声明为public,表示允许在类外部实例化,构造函数不允许有返回值。如下,构造函数在函数体内初始化类的实例成员,前提是这些程序是public
静态构造函数

静态构造函数会初始化类的静态字段。
静态构造函数由系统会自动调用。
它的调用在引用任何静态成员之前,在创建类的任何实例之前(也就是说会在普通构造函数之前)。
一个类只能有一个静态构造函数,并且不能有参数,也不能有访问修饰符。
不能访问所在类的实例成员。

readonly

表示只读的,它的效果和const效果一样,不过readonly更像是把变量标注为只读。
const需要在声明语句中初始化,而readonly可以在声明语句初始化,也可以在构造函数中初始化,都不可以在函数成员中初始化
const的值只能在编译时决定,而readonly可以再运行时决定。
const总是静态的,readonly可以是实例,也可以用static修饰为静态,
const在内存中没有存储位置,readonly有存储位置。

this关键字

this关键字在类中使用,用来引用当前的实例,相对的,它无法引用静态字段;同时由于静态函数成员无法使用实例成员,因此this关键字无法在静态函数成员中使用。
this关键字的主要作用就是区分成员和本地变量。

索引器

索引器可以让我们以数组访问的行书对实例的成员字段进行操作,索引器跟属性很类似,可以说属性是为一个数据成员提供get和set,索引器为多个相同类型的成员提供get和set。
它有许多和属性一样的性质,不过,它不能声明为static。
下面是一个索引器的例子

    class QuickSort
    {
        private string str1;
        private string str2;
        private string str3;

        //注意,与属性不同的是,索引器没有名字,使用this关键字,后面跟上中括号,里面是一个索引
        public string this[int idx]
        {
            set
            {
                switch (idx)
                {
                    case 0: str1 = value; break;
                    case 1: str2 = value; break;
                    case 2: str3 = value; break;
                    default:
                        break;
                }
            }
            get
            {
                switch (idx)
                {
                    case 0: return str1;
                    case 1: return str1;
                    case 2: return str1;
                    default:
                        return null;
                }
            }
        }

下面是使用这个索引器

QuickSort sort = new QuickSort();
sort[0] = "abc";
sort[1] = "bcs";
sort[2] = "saa";
string s = sort[2];
string s2 = sort[0];

索引器可以重载,如果重载,需要有不同的参数列表。


分部类

分部类使用partial修饰符,分部类可以让一个类分在几个文件中完成,在socket网络游戏编程这部书中,处理协议的函数就是写在一个类的许多分部类中。
分部方法

分部方法是在分部类中,分部方法把一个方法分割为一个方法的声明,和一个方法的实现。它有以下几个要求:
1、返回类型必须是void。
2、签名不能包括访问修饰符,也就是说分部方法是分部类的隐式私有的。
3、参数列表不能包含out参数。
4、声明个实现部分都是用partial上下文关键字,放在void前面。

如下是一个分部方法:

——继承

可以使用父类引用,子类实例,因为子类包含父类需要的一切,在子类实例化时,有一部分是基类,所以基类可以去引用;但是基类实例化是没有派生类的,所以不可以反过来。

new和virtual、override的区别

new和virtual、override容易让人混淆头晕
首先new关键字用于派生类不希望使用基类的成员(函数成员字段成员都可以使用,不能对static使用)时,可以做到屏蔽的作用,不会干扰到基类的成员。比如:

    class Base
    {
        public string str = "base";
        public void Print()
        {
            Console.WriteLine(str);
        }
    }
    class Child : Base
    {
        new public string str = "child";
        new public void Print()
        {
            str += " this";
            Console.WriteLine(str);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Base bas = new Base();
            Child child = new Child();
            Base bas1 = new Child();
            bas.Print();    //打印base
            child.Print();  //打印child this
            bas.Print();    //打印base

            Console.ReadLine();
        }
    }

而virtual、override只能作用于函数成员,如方法,属性等,不能重写static类型,虽然也能做到派生类屏蔽基类成员的作用,这与new关键字效果相同。但是更重要的是,在父类引用,派生类实例时,创建的对象会向上找,找到最高的那个重写(忽视低的)然后调用。

   class Base
    {
        public string str = "base";
        virtual public void Print()
        {
            Console.WriteLine(str);
        }
    }
    class Child : Base
    {
        override public void Print()
        {
            string str = "child";
            Console.WriteLine(str);
        }
    }
    class Second : Child
    {
        public override void Print()
        {
            string str = "second";
            Console.WriteLine(str);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Base bas = new Base();
            Child child = new Child();
            Second second = new Second();
            Base bas1 = new Child();
            Base bas2 = new Second();
            Child child1 = new Second();

            bas.Print();        //打印base
            child.Print();      //打印child
            second.Print();     //打印second
            bas1.Print();       //打印child
            bas2.Print();       //打印second
            child1.Print();     //打印second

            Console.ReadLine();
        }
    }
构造函数的执行

在继承链中,每个类执行自己的构造函数体之前都会执行其基类的构造函数。因此,不要在基类构造函数中调用虚函数,因为基类构造函数执行时,调用虚函数,而派生类还没有完全初始化。

派生类使用基类构造函数有两种形式,第一种是使用base,第二种是使用this。一般都是用base,this更好的用法是用在一个类拥有多个构造函数时,把多个构造函数相同的部分提取出来,然后其他构造函数通过this使用这个提取出来的构造函数,如下:

    class Base
    {
        public string str = "base";
        public Base()
        {
            str = "new base";
        }
        public Base(string str) : this()//通过this使用其他的构造函数
        {
            Console.WriteLine(str + this.str);
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            Base bas = new Base("this ");//打印this new base
            
            Console.ReadLine();
        }
    }
抽象类和抽象函数成员

使用abstract关键字修饰。
抽象类有以下要求:
1、不能被实例化。
2、主要用途用于被继承,并且抽象类可以继承其他抽象类。
3、抽象类既可以有抽象函数成员,又可以有普通函数成员。
抽象函数成员:
1、只能有签名,不能有函数体。
2、只能设置函数成员(方法,属性,事件,索引器),不能设置字段成员。
3、继承该抽象类,必须重写所有的抽象函数成员。

密封类

使用sealed关键字修饰,表示这个类不允许类继承。

静态类

静态类就是用static修饰的类,主要用途就是作为工具类,具有以下特点:
1、所有成员必须全部都是静态的,不允许普通成员。
2、静态类不允许被继承,也就是隐式密封类。

3、可以有一个静态构造函数,但是不允许有普通构造函数,因为不允许实例化。
扩展方法

这是一个十分实用的功能
它的作用是让你可以向第三方的静态类中添加我们自己定义的函数,然后依然通过第三方静态类调用。它有几个条件:
1、扩展方法必须卸载静态类中。
2、扩展方法必须包含关键字this的参数作为第一个参数,并在后面跟上要扩展的类的类的名称和引用。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容