接口的继承
使用率不太高
A接口继承B接口,A接口拥有A和B的接口功能
一个类可以实现多个接口,用,分开
接口的继承
使用率不太高
A接口继承B接口,A接口拥有A和B的接口功能
一个类可以实现多个接口,用,分开
接口
也是一种类,只包含没有实现的方法,没有数据成员
不能有构造函数,没有字段,无法进行运算符重载
接口的所有方法都是pubilc
interface 建议取名前面加I,例如IPort
继承接口类(准确来说是实现接口),必须重写接口中所有的方法
相当于USB接口,不实现任何功能,但可以插入各种功能
添加新项-接口
直接点击小灯泡可以自动帮忙实现接口
只能继承单个类,但可以实现多个接口
直接创建接口变量
面向接口编程
接口可以直接声明一个对象。
用这个对象可以创建的多个实例。
这个对象创建的实例,这些实例都可以实现接口的功能。
以上的说法不太准确,应该是:
1、接口可以声明为变量类型,这个变量可以引用实现了该接口的类的实例
2、接口实现方式:定义接口-创建实现类(可以是多个)-实例化具体类(new)-通过接口变量来实现类
实现多态
用接口变量来调用任意一个实例
抽象隔离原则
接口的设计目的就是隐藏具体实现细节,只暴露契约(方法签名)。调用方只需知道"这个对象能飞行",而不需关心是飞机还是鸟。
运行时绑定
具体调用哪个实现,是在运行时动态决定的(根据当前引用的对象类型)。编译时只检查接口契约是否满足。
static 静态修饰符
静态变量(数据成员)
类中存在静态变量,则在各个类中内共享,存储在静态存储区中(被多个类共享,全局)
只能通过类名来访问,无法通过实例引用访问(C#和JAVA的不同)
静态函数能够调用静态变量,不能访问动态变量
静态类
只能使用静态成员(方法和数据)
无法被实例化(直接调用)
无法被继承
不能声明构造函数(可以静态构造函数)
new
abstract 和override一起使用
sealed(必须和override)
static 修饰类或数据成员
const 常量(必须初始化)
readonly(初始化或构造函数里赋值,后面无法修改)
virtual 虚方法,和override一起使用
abstract和virtual:必须强制实现、允许覆盖
internal和public,是否可以在同一个程序集(项目)内访问
类的public(默认不是),实现项目之间的共享,右键“添加项目引用”(选取其他项目,并且会自动添加依赖项)
using 命名空间;
子类的访问权限不能比父类高
先调用父类中的构造函数,再调用子类中的构造函数
public DrivedClass():base(){}
如果重载了构造函数
构造函数时候,可以使用冒号,将子类传入的参数传入父类的参数中。
传递到父类构造函数的参数不会自动赋值给子类,子类需单独处理自己的参数。
抽象类
定义类的时候,添加abstract关键字
1、类似虚函数virtual,但必须被重写
2、抽象方法可以没有函数体
3、只能被继承,无法被实例化
只有abstract抽象类中,才能创建抽象方法
如果继承了抽象类,那必须实现抽象类中的抽象方法。
throw 抛出异常
密封类、密封方法
Sealed
密封类无法被继承
密封方法:
1、父类中必须包含vitual虚函数或abstract抽象方法
2、子类中进行override的时候,添加Sealed可以让其无法被再次重写(避免方法被多次重写,代码混乱)
sealed 是 override
的修饰,所以必须sealed override
隐藏方法和虚方法的区别
public new void 方法()
实际上是新建了一个方法
方法一:
使用new方式来实现重写
public new void CarInfo()
但严格意义上来说并不是重写,而是隐藏原有的方法新建一个同名的方法
方法二:
使用虚函数+override的方法来实现重写
1、首先要在父类中将可以重写的方法设置为vitual
2、在子类中使用override的方法进行重写
声明父类enemy,但构造的时候以子类enemy = new Boss(); 那么enemy构造后的实例就是子类
在 C# 中,当你使用 Enemy enemy = new Boss();
时,虽然实际创建的是 Boss
的实例,但通过 Enemy
类型的变量 enemy
访问它时,只能调用 Enemy
类中定义的方法和属性,无法直接访问 Boss
特有的成员。这是由 C# 的编译时类型检查和多态机制决定的。
Enemy enemy = new Boss();
这种写法看似反直觉,但它在面向对象编程(尤其是多态)中扮演着核心角色。是否需要避免这种写法,完全取决于具体场景。
核心目的:通过父类引用统一管理不同子类对象,运行时自动调用子类重写的方法。
this 可以访问本地类
base 专门用来访问父类,一般用来重写方法,很少用来重写数据
类中的访问权限
protected 只能被自己的成员访问
继承类的语法
Class 派生类名称:基类名称{}
子类继承父类,不能访问父类的私有数据成员(封装),但并不是无法访问,而是没有访问权限
继承
1、实现继承
2、接口继承
实现继承
基类(父类)、派生类(子类)
重写函数(方法)
多重继承的优缺点:C++,功能强大代码紧凑,多个父亲。C#、JAVA不支持。
但是,多重接口继承可以继承。
Object 是所有类的基类
将对象A赋值给对象B,对象B内的值修改,也会影响到对象A
赋值操作并没有创建一个新的对象(只有new才会创建新的对象),只是将内存引用地址赋值给了对象B
new 之后的对象,都存放在堆里面
对象名存放在栈中,对象的内容存放在堆之中
一个对象会被多个引用,GC将引用的数量做成计数器,当计数器为0后,则会被回收
类的空引用
c1 = null;
两个字符串类型的变量,对应的内容是一样的(处于静态存储区中的字符串)
静态存储区的内容是不可修改的
修改字符串变量只是修改了引用,而并没有修改字符串内容本本身(存在静态存储区)
栈:变量
堆:数组内容
静态存储区:字符串常量(节约内存空间,复用)
VS的自动生成功能
(右键)快速操作和重构-生成构造函数
GC 垃圾回收器
CLR是GC的内存管理机制
数据类型
1、值类型:枚举(对应一个数字)、结构体
2、引用类型:字符串(对应一个ASCII码)、数组、类
值类型:单独内存
引用类型:两段内存,1-实际数据(堆),2-指针(堆中的位置)
调试模式下显示内存信息,直接拖拽变量到窗口内,可查看内存地址
get 和 set 可以简写(不写任何方法)
通过创建属性,自动创建数据成员
var 匿名类型(不指定类型,根据后面的值来确定类型,确定之后就无法更改了)
数据成员一般都用private
使用set、get来获取和修改
void set
int get
通过定义一个属性,可以实现set和get(相当于这两个方法的简写)
set中,直接使用自带的value参数,给数据成员赋值
get中,可以直接return对应的数据成员,获取该数据成员的值
外部使用的时候,可以直接.属性值来使用对该属性的调用,调用其属性可以实现get方法,对其赋值可以实现set方法
另外,可以在set和get中继续撰写代码来实现功能(例如数值校验)
set和get可以设置为private,则外部访问时就会报错
如果我们定义了有参数的构造函数之后,创建类对象的时候就必须写上对应的参数,否则就会出错。
(VS会在创建对象的时候自动提示参数)
this 表示的当前对象(只有类中有这个参数,方法中并不含this)