接口 继承 索引器 运算重载符 结构体和类的不同

接口

什么是接口

在这里插入图片描述
说明:接口也是一个类,但是接口里只包含没有实现的方法

习惯上,接口用 I 来打头,表示他是一个接口,而不是一个类

定义接口

public interface IFlyHandler{
public void Fly();
}

实现接口

public class Type1Enemy:IFlyHandler{
}

接口指定了一个方法,但是具体是什么方法,接口是不管的,在实现接口的时候,方法就实现了

定义⼀个接⼝在语法上跟定义⼀个抽象类完全相同,但不允许提供接⼝中任何成员的实现

⽅式

接口不能有构造函数

也不能有字段,不允许运算符重载

创建接口的操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IU6sCG7o-1680780500883)(C:\Users\CoreDawg\AppData\Roaming\Typora\typora-user-images\image-20230406165142267.png)]

右键选择新建项而不是类,然后选择接口,注意开头用I标注

创建接口的代码

using System;
using System.Collections.Generic;
using System.Text;

namespace 接口
{
    interface IFly
    {
        //一个接口可以包含多个方法
        void Fly();//即使不加 public 也默认是一个public属性的函数
        void FlyAttack();
        //接口只包含函数的声明,不包含函数的函数体
    }
}

接口实现的操作

创建两个类来实现接口的方法[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HedBMW9P-1680780500885)(C:\Users\CoreDawg\AppData\Roaming\Typora\typora-user-images\image-20230406170036773.png)]

冒号继承之后,点击灯泡 - 实现接口

就能自动帮助实现

namespace 接口
{
    class Plain : IFly
    {
        public void Fly()
        {
            Console.WriteLine("飞机飞行");
        }

        public void FlyAttack()
        {
            Console.WriteLine("飞机攻击");

        }
    }
}
class Bird : IFly
    {
        public void Fly()
        {
            Console.WriteLine("小鸟飞行");
        }

        public void FlyAttack()
        {
            Console.WriteLine("小鸟攻击");

        }
    }

使用接口

单独使用plain的接口

 static void Main(string[] args)
        {
            //单独使用飞机的接口
            Plain p = new Plain();
            p.Fly();
            p.FlyAttack();
            //输出 飞机飞行 飞机攻击

        }

使用接口声明对象

 //使用接口声明对象
            IFly fly;
            fly = new Plain();//把飞机赋值给接口声明的对象,这样这个对象就有了飞机的特性
            fly.Fly();
            fly.FlyAttack();
            //输出 飞机飞行 飞机攻击

使用接口声明的对象,需要指定具体是哪个接口,因为接口之间的功能名是重复的

多态

//使用接口声明对象
            IFly fly;
            fly = new Plain();//把飞机赋值给接口声明的对象,这样这个对象就有了飞机的特性
            fly.Fly();
            fly.FlyAttack();
            //输出 飞机飞行 飞机攻击

            fly = new Bird();
            fly.Fly();
            fly.FlyAttack();
            //输出 小鸟飞行 小鸟攻击

接口的形态发生了变化

接口的继承

接⼝可以彼此继承,其⽅式和类的继承⽅式相同

public interface A{
void Method1();
}
public interface B:A{
void Method2();
}

演示:

接口1

    interface Interface1
    {
        void Method1();
    }

接口2可以继承接口1

    interface Interface2:Interface1//接口的继承
    {
        void Method2();
    }

这时候接口2就有了接口1的方法声明

这样的话实现的话,就要同时实现两个方法

 class ClassInterface : Interface2
    {
        public void Method1()
        {
            throw new NotImplementedException();
        }

        public void Method2()
        {
            throw new NotImplementedException();
        }
    }

类可以实现多个接口

class ClassInterface : Interface2,Interface1//实现多个接口

什么是索引器

通过索引访问变量的操作

            //演示数组
            int[] array = { 123, 22, 33, 55, 92, 9, 1, 3, 13, };

            //通过索引访问变量
            Console.WriteLine(array[1]);

//使用索引器赋值

定义索引器

public int this[int index]
        {
            get//取值 调用
            {
                return 100;//需要返回值
            }
            set//赋值
            {
                //value 设置的时候会传递value这个参数
                Console.WriteLine(value);

            }
        }

索引调用的演示

 Test t = new Test();
            t[9] = 200;//当你使用索引的时候,会把索引给到index

输出调用的索引

 public int this[int index]
        {
            get//取值 调用
            {
                Console.WriteLine(index);
                return 100;//需要返回值
            }
            set//赋值
            {
                //value 设置的时候会传递value这个参数
                Console.WriteLine(value);
                Console.WriteLine(index);

            }
        }

用索引取值

            Console.WriteLine(t[9]);

索引器的作用

在类里先声明一个数组

        //长度为10的名字 字符串数组
        public string[] name = new string[10];

可以利用索引器往这个里面赋值,也可以利用索引器往这个里面取值

public string this[int index]
        {
            get
            {
                return name[index];
            }
            set
            {

                name[index] = value;//把用户给到的value设定到用户取值的位置
            }
        }
            //Test就相当于一个数组管理器了
            Test t = new Test();
            t[0] = "张三";
            t[1] = "李四";

            //取值
            Console.WriteLine(t[1]);
            Console.WriteLine(t[0]);

直接定义一个字符串数组更方便

            string[] name = new string[10];
            name[0] = "sahidha";
            name[1] = "16513";

星期和数字转换器

先定义一个数组保存星期几的英文字符

    class Week
    {
        private string[] days = { "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat", "Sun" };//索引加1就是周几

        public int GetDay(string day)
        {
            int i = 0;
            foreach(string temp in days)
            {
                if (temp == day) return i+1;
                i++;
            }
            return -1;
        }

    }

使用

            Week w = new Week();
            Console.WriteLine( w.GetDay("Thurs"));

使用索引器

        public int this[string day]
        {
            get
            {
                return GetDay(day);
            }
        }
            Week w = new Week();
            Console.WriteLine( w["Thurs"]);

什么是运算符重载

什么是运算符?

± * / %

设定个学生的构造函数和成员

    class Student
    {
        private int age;
        private string name;
        private long id;

        public Student(int age, string name, long id)
        {
            this.age = age;
            this.name = name;
            this.id = id;
        }
    }

判断两个数据完全一样的学生是否相等

        static void Main(string[] args)
        {
            //s1 s2 数据完全相等
            Student s1 = new Student(20, "shdiah", 32512);
            Student s2 = new Student(20, "shdiah", 32512);

            //判断s1 s2是否相等
            Console.WriteLine(s1 == s2);//得到结果False

        }

说明:变量在创建对象的时候在 堆 里创建了两个对象

在 栈 里存储的两个地址也不一样

在做比较的时候比较的是地址,故得到False

那么直接吧s1赋值给s3呢,这样的话两个对象一样吗

            Student s3 = s1;
                        Console.WriteLine(s1 == s3);//得到结果True

说明:两个等号比较的时候比较的就是引用地址,如果s3和s1的引用一样,故得到True

运算重载符的例子

以上的比较都是比较的引用地址,那么如何比较两个的对象的数据呢,这时候就需要用到运算重载符

        //运算重载符的书写
        public static bool operator==(Student s1,Student s2)//需要重写的符号要写在关键字 operator 后面
        {
            //用三个条件去比数据
            if (s1.age == s2.age && s1.id == s2.id && s1.name == s2.name)
            {
                return true;
            }
            return false;
        }

==和!=需要成对的书写

        public static bool operator!=(Student s1, Student s2)
        {
            //可以直接调用上面的函数判断
            bool result = s1 == s2;
            return !result;
        }

对比方法重新调用

Console.WriteLine(s1 == s2);

面向对象练习题1

*1.C#中的方法重写使用关键字()。*

override

*2. 以下的C#代码,试图用来定义一个接口:*

*public interface IFile{*

*int A;*

*int delFile()* *{*

*A = 3;*

*}*

*void disFile();*

*}*

*关于以上的代码,以下描述错误的是(d)。(选择一项)*

a) 以上的代码中存在的错误包括:不能在接口中定义变量,所以int A代码行将出现错误

b) 以上的代码中存在的错误包括:接口方法delFile是不允许实现的,所以不能编写具体的实现函数

c) 代码void disFile();定义无错误,接口可以没有返回值

d) 代码void disFile();应该编写为void disFile(){};

*3.在C#中,接口与抽象基类的区别在于(a)。*

a) 抽象基类可以包含非抽象方法,而接口只能包含抽象方法

b) 抽象基类可以被实例化,而接口不能被实例化

c) 抽象基类不能被实例化,而接口可以被实例化

d) 抽象基类就是接口,它们之间无差别

*4.在开发某图书馆的图书信息管理系统的过程中,开始为教材类图书建立一个TextBook类;现在又增加了杂志类图书,于是需要改变设计,则下面最好的设计应该是(c)。*

a) 建立一个新的杂志类Journal。

b) 建立一个新的杂志类Journal,并继承TextBoook类。

c) 建立一个基类Book和一个新的杂志类Journal,并让Journal类和TextBoook类都继承于Book类。

d) 不建立任何类,把杂志图书的某些特殊属性加到TextBoook类中。

*5.可以使用(override)关键字重写方法。*

a) Override

b) New

*6**.以下叙述正确的是:(bc)*

A.接口中可以有虚方法。 B.一个类可以实现多个接口。

C.接口不能被实例化。 D.接口中可以包含已实现的方法。

*7**.下列代码输出为( b):*

class Father{

public void F() { Console.WriteLine(“A.F”); }

public virtual void G() { Console.WriteLine(“A.G”); }

}

class Son: Father{

new public void F() { Console.WriteLine(“B.F”); }

public override void G() { Console.WriteLine(“B.G”); }

}

class override_new{

static void Main() {

Son b = new Son();

Father a = b;

a.F();

b.F();

a.G();

b.G();

}

}

A. A.F B.F A.G B.G

B. A.F B.F B.G B.G

C. A.F A.F B.G B.G

D. B.F B.F B.G B.G

*8**.写出程序的输出结果:*

public class A

​ {

​ public virtual void Fun1(int i)

​ {

​ Console.WriteLine(i);

​ }

​ public void Fun2(A a)

​ {

​ a.Fun1(1);

​ Fun1(5);

​ }

​ }

​ public class B:A {

​ public override void Fun1(int i)

​ {

​ base.Fun1(i+1);

​ }

​ public static void Main() {

​ B b=new B();

​ A a=new A();

​ a.Fun2(b);

​ b.Fun2(a);

​ }

}

答案:2 5 1 6

*9**.在C#中,允许多接口继承,从多个接口时,使用“:”后跟继承的接口的名字,多个接口名称之间使用(c)符号进行分割。(选择一项)*

a)”.’

b)”->”

c)”,”

d)”::”

*1**0**.阅读以下的C#代码:*

class A

​ {

​ public virtual void printStr(string str)

​ {

​ Console.WriteLine(str);

​ }

​ }

​ class B:A

​ {

​ public override void printStr(string str)

​ {

​ str=str+" 重写的方法";

​ Console.WriteLine(str);

​ }

​ }

​ class DefaultInitializerApp

​ {

​ public static void Main()

​ {

​ B b=new B();

​ A a=b;

​ a.printStr(“打印”);

​ b.printStr(“打印”);

​ Console.ReadLine();

​ }

​ }

运行程序后将在控制台窗口打印(a )。(选择一项)

a. 打印 重写的方法 打印 重写的方法

b. 打印 打印 重写的方法

c. 打印

d. 程序有误,不能运行

*1**1**.在C#的语法中,(a)关键字可以实现在派生类中对基类的虚函数进行重载(选一项)*

a> override

b> new

c> static

d> virtual

*1**2**.请问,此程序输出结果是©*

abstract class BaseClass{

public virtual void MethodA(){Console.WriteLine(“BaseClass”);}

public virtual void MethodB(){}

}

class Class1: BaseClass{

public void MethodA(){Console.WriteLine(“Class1”);}

public override void MethodB(){}

}

class Class2: Class1{

new public void MethodB(){}

}

class MainClass{

public static void Main(string[] args){Class2 o = new Class2();o.MethodA(); }

}

A. BaseClass

B. BassClass Class1

C. Class1

D. Class1 BassClass

*1**3**.请问,此程序输出结果是(a)*

public abstract class A { public A() { Console.WriteLine(‘A’); }

public virtual void Fun() { Console.WriteLine(“A.Fun()”); } }

public class B: A { public B() { Console.WriteLine(‘B’); }

public new void Fun() { Console.WriteLine(“B.Fun()”); }

public static void Main() { A a = new B();a.Fun(); } }

A. A B A.Fun()

B. A B B.Fun()

C. B A A.Fun()

D. B A B.Fun()

*14**.以下叙述正确的是(bc):*

A. 接口中可以有虚方法。

B. 一个类可以实现多个接口。

C. 接口不能被实例化。

D. 接口中可以包含已实现的方法。

*15**.以下关于C#代码的说法正确的是(a)。(选择一项)*

Public abstract class Animal

{

​ Public abstract void Eat();

​ Public void Sleep()

{

}

}

a. 该段代码正确

b. 代码错误,因为类中存在非抽象方法

c. 代码错误,因为类中的方法没有实现

d. 通过代码“Animal an = new Animal();”可以创建一个Animal对象

*16**.在c#中,关于继承和接口,以下说法正确的是() (b)*

a. c#允许许多接口实现,也允许多重继承

b.c#允许多接口实现,但不允许多重继承

c.c#不允许多接口实现,但允许多重继承

d.c#不允许多重接口实现,也不允许多重继承

*17.* *在C#中,已知下列代码的运行结果是“老虎吃动物”,请问在空白处1和空白处2*

*分别应该填写的代码是(c

)*

​ Public class Animal

​ {

​ Public 空白处1 void Eat()

​ {

​ Consone.WriteLine(“我要吃”);

}

}

Public class Tiger:Animal

​ {

​ Public 空白处2 void Eat()

​ {

​ Consone.WriteLine(“老虎吃动物”);

}

Public calssTest

{

​ Static void Main()

​ {

​ Animal an = new Tiger();

​ an.Eat;

}

}

}

a) Virtual , new

b) override , virtual

c) virtual , override

d) new , virtual

*18.* *在C#中,下列关于抽象类和接口的说法,正确的是)(b)(选择一项)*

​ a) 在抽象类中,所以的方法都是抽象方法

​ b) 继承自抽象类的子类必须实现起父类(抽象类)中的所以抽象方法

​ c) 在接口中,可以有方法实现,在抽象类中不能有方法实现

​ d) 一个类可以从多个接口继承,也可以从多个抽象类继承

*19.* *关于以下C#代码的说法正确的是()*

Public abstract class Animal{

​ Public abstract void Eat();

}

Public class Tiger:Animal{

​ Public override void Eat(){

​ Console.WriteLine(“老虎吃动物”);

}

}

Public class Tigress:Tiger{

​ Static void main(){

​ Tigress tiger=new Tigress();

Tiger.Eat();

}

}

a. 代码正确,但没有输出

b. 代码正确,并且输出为”老虎吃动物”;

c. 代码错误,因为Tigress类没有实现抽象基类Animal中的抽象方法

d. 代码错误,因为抽象基类Animal的Eat方法没有实现

结构体和类的不同

类的情况

 static void Main(string[] args)
        {
            //创建两个类的对象
            Student stu1 = new Student(18,"小芳");
            Student stu2 = new Student(25,"小刚");

            stu2 = stu1;

            stu1.age = 30;
            stu1.name = "小燕";
            Console.WriteLine(stu2.name);
            Console.WriteLine(stu2.age);
        }

数据也跟着改变了

说明:因为s1s2都是指向同一个地址的,因此只修改一个地址的数据,两边会跟着改

结构体的情况

声明一个结构体

    //定义一个结构体
    struct StudentSt
    {
        public int age;
        public string name;

        //结构体里面也可以有构造函数
        public StudentSt(int age, string name)
        {
            this.age = age;
            this.name = name;
        }
    }

结构体的存放

            StudentSt stu1 = new StudentSt(18, "小芳");//因为结构体是值类型的,所以他不会在 堆 里存放 而是在 栈 里存放
            //StudentSt stu2 = new StudentSt(25, "小刚");
            StudentSt stu2 = stu1;//把里面的每个数据单独赋值
            //stu1 stu2 是在 栈 里面不同区域存储的
            //并不是像在类里一样赋值了地址引用
            //因此就算此时修改s1,也对s2,没有影响
            stu1.age = 30;
            stu1.name = "小燕";

            Console.WriteLine(stu2.age);
            Console.WriteLine(stu2.name);
            //输出结果仍然是18 小芳

.name = “小燕”;
Console.WriteLine(stu2.name);
Console.WriteLine(stu2.age);
}


数据也跟着改变了

说明:因为s1s2都是指向同一个地址的,因此只修改一个地址的数据,两边会跟着改

### 结构体的情况

声明一个结构体

```C#
    //定义一个结构体
    struct StudentSt
    {
        public int age;
        public string name;

        //结构体里面也可以有构造函数
        public StudentSt(int age, string name)
        {
            this.age = age;
            this.name = name;
        }
    }

结构体的存放

            StudentSt stu1 = new StudentSt(18, "小芳");//因为结构体是值类型的,所以他不会在 堆 里存放 而是在 栈 里存放
            //StudentSt stu2 = new StudentSt(25, "小刚");
            StudentSt stu2 = stu1;//把里面的每个数据单独赋值
            //stu1 stu2 是在 栈 里面不同区域存储的
            //并不是像在类里一样赋值了地址引用
            //因此就算此时修改s1,也对s2,没有影响
            stu1.age = 30;
            stu1.name = "小燕";

            Console.WriteLine(stu2.age);
            Console.WriteLine(stu2.name);
            //输出结果仍然是18 小芳
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值