C# 面向对象三大基本特性
封装、继承、多态
1、封装
隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。
C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。
一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:
● public:所有对象都可以访问;
● private:对象本身在对象内部可以访问;
● protected:只有该类对象及其子类对象可以访问;但不可以继承给子类
● internal:同一个程序集的对象可以访问;
● protected internal:访问限于当前程序集或派生自包含类的类型。
读写性
只读 readonly : {get;}
只写 writeonly : {set;}
读写 read-write : {get;set;}
2、继承
继承有一个很重要的原则,叫里氏替换原则:子类是父类;
如:
麻雀:鸟(麻雀继承鸟类),可以说,麻雀是鸟,但不能说鸟是麻雀。
在代码里也一样。
//前提:Eagle:Bird
var lstBird = new List<Bird>();
Eagle b1 = new Eagle();
lstBird.Add(b1);//是没毛病的
因为Eagle是Bird,所以List< Bird> 可以添加Eagle。Eagle拥有所有Bird需要的成员,包括private成员。
实际上,子类能继承父类除了构造函数以外的所有成员,public\protected\private等,与继承没有关系,仅是访问的可见性。子类能继承父类成员访问性的所有特性。但对于private,又有比较特殊的地方:子类无法访问到父类的private成员,也就是说在子类新建一个同名的成员,编辑器是不会提示重名的。但是实际上父类的private成员是被继承了的,只不过子类无法看到而已。如父类有一个private成员Color,如果父类的函数有一个WriteLine这个成员的函数,如果子类不重写此函数,输出是父类的Color;如果子类重写了,就算函数内容完全一致,输出的也是子类的Color;
父类的属性、方法会继承给子类,子类中可以访问直接访问public\internal的成员,但是无法直接访问private的成员。对于protected修饰的成员,只有在自己的作用范围内访问到protected的成员。也就是说,只有在代码Class {——–}内部,可以直接访问到protected成员,而当你在实例化类 时,你就不可以访问该成员了。
同理也继承到了子类处。
如
class Bird
{
public Bird(string sName,int sSize)
{
Name = sName;
Size = sSize;
}
protected string Name;
public int Size;
public virtual void Cry()
{
Console.WriteLine("i am Bird");
}
public void GetName()
{
Console.WriteLine(Name);
}
}
class Eagle : Bird
{
public Eagle(string Name, int Size) : base(sName: Name, sSize: Size){}
public override void Cry()
{
Console.WriteLine($"i am {Name} ! come ,chickens");
}
}
在Eagle类的内部,重写了Cry方法,可以直接访问到继承的protected成员Name。
而在
class Program
{
static void Main(string[] args)
{
var b1 = new Eagle("Huge",75);
var b1Name = b1.Name;
}
}
在上述代码中则会报错:
仅能在内部访问,实例化后的成员不可访问。
3、多态
简单来说,多态指同一个实体同时具有多种形式。
重写 是多态的一个重要形式。
父类有一个virtual的方法,则子类可以继承并重写这个方法。
我举个例子。
class Program
{
static void Main(string[] args)
{
var birdList = new List<Bird>();
var b1 = new Eagle("Huge",75);
var b2 = new Sparrow("Tiny", 12);
birdList.Add(b2);
birdList.Add(b1);
foreach (var b in birdList)
{
b.Cry();
}
Console.Read();
}
}
class Bird
{
public Bird(string sName,int sSize)
{
Name = sName;
Size = sSize;
}
protected string Name;
public int Size;
public virtual void Cry()
{
Console.WriteLine("i am Bird");
}
public void GetName()
{
Console.WriteLine(Name);
}
}
class Eagle : Bird
{
public Eagle(string Name, int Size) : base(sName: Name, sSize: Size){}
public override void Cry()
{
Console.WriteLine($"i am {Name} ! come ,chickens");
}
}
class Sparrow : Bird
{
public Sparrow(string Name, int Size) : base(sName: Name, sSize: Size) { }
public override void Cry()
{
Console.WriteLine($"i am {Name} ! ");
}
}
操作结果如下:
即:不同的基类的同名方法实现了不同的操作,这就是重写,多态的体现。
多态还有其他体现方式,下回再补充。
补充一下:重载
重载与重写不同,重载是同名方法不同参数而体现出不同的操作,构造函数就是一个例子。一个类可以有多个构造函数,参数类型、参数个数成为区别函数主体的条件。