对C#面向对象三大特性的一点总结
一、三大特性
封装: 把客观事物封装成类,并把类内部的实现隐藏,以保证数据的完整性
继承:通过继承可以复用父类的代码
多态:允许将子对象赋值给父对象的一种能力
二、【封装】特性
把类内部的数据隐藏,不让对象实例直接对其操作,通过给类及类中的成员变量、属性和方法设置不同的访问修饰符(public、protected、internal、
protected internal、private)来控制它们的作用范围,以达到封装的目的。
实例:
(1) 没有封装的类:
1 public class Animal 2 { 3 public string _name; 4 public int _age; 5 } 6 static void Main(string[] args) 7 { 8 Animal animal = new Animal(); 9 animal._name = "sheep"; 10 animal._age = -1; 11 }
(2) 封装后的类:
1 public class Animal 2 { 3 private string _name; 4 private int _age; 5 6 public string Name 7 { 8 get { return _name; } 9 set { _name = value; } 10 } 11 12 public int Age 13 { 14 get { return _age; } 15 set 16 { 17 if (value < 0 || value > 10) 18 { 19 throw (new AggregateException("年龄必须在0~10岁之间!")); 20 } 21 _age = value; 22 } 23 } 24 }
二、【继承】特性
1、通过继承,程序可实现对父类代码的复用,子类继承父类的所有成员(构造函数 、析构函数、静态类、密封类除外),子类无需再定义父类中已有定义的代码。
2、被继承的类成为父类、基类、超类,而主动继承的类成为子类或派生类,Object是所有类的基类。
3、当父类和子类中有名称相同的方法时,父类中的方法会被隐藏
4、里氏替换原则:子类对象可以赋值给父类变量,反之不成立
5、子类不能对父类的私有成员进行访问,只能对公有成员和保护成员访问,但子类可以通过调用公有成员或保护方法间接的对私有成员进行访问
实例:
1 //基类:Animal 2 public class Animal 3 { 4 private string _name; 5 private int _age; 6 7 public string Name 8 { 9 get { return _name; } 10 set { _name = value; } 11 } 12 13 public int Age 14 { 15 get { return _age; } 16 set 17 { 18 if (value < 0 || value > 10) 19 { 20 throw (new AggregateException("年龄必须在0~10岁之间!")); 21 } 22 _age = value; 23 } 24 } 25 } 26 27 //子类:羊 28 public class Sheep : Animal 29 { 30 31 } 32 33 //子类:马 34 public class Horse : Animal 35 { 36 37 } 38 39 static void Main(string[] args) 40 { 41 Sheep sheep = new Sheep(); 42 sheep.Name = "Xi Yangyang"; 43 sheep.Age = 5; 44 45 Horse horse = new Horse(); 46 horse.Name = "Qian Li"; 47 horse.Age = 6; 48 }
三、【多态】特性
1、相同类型的对象调用相同的方法表现出不同的行为。
2、两种表现形式:重载、重写
3、重载:同一个类中有多个方法的名称相同、参数个数不同或类型不同
4、重写:使用 virtua l和 override 关键字实现方法重写,只有基类成员声明为virtual 或 abstract,才能被派生类重写。
5、以下3种情况重写:
a、当类为普通类时,只有父类的虚方法才能被子类重写,子类实现重写要用关键字override,如果不加override就会隐藏父类的方法,
隐藏需要加上关键字new,例如:
public new static void a()
{
}
或
public static new void a()
{
}
静态类中只能有静态成员,非静态类中可以有静态成员和非静态成员。
静态方法不能被重写,但可以被隐藏。
静态成员不能带override、abstract、virtual。
b、抽象类中可以有抽象属性、抽象方法和成员实例,继承抽象类的子类必须直接或间接重写所有的抽象方法,而且参数和返回值类型必须完全一致,
成员实例可以不被重写。
非抽象类中只能有成员实例。
抽象类不能直接实例化,但是有构造方法,可以利用里氏替换原则把子类对象赋值给抽象的父类变量。
抽象方法必须用abstract修饰,而且不能有方法体。
抽象方法不能用private修饰。
c、类是单继承,接口是多继承,如果同时继承类和接口的话,接口必须在基类的后面,否则编译会出错。
接口不能直接实例化,没有构造方法,可以利用里氏替换原则把子类对象赋值给接口类型的父类变量。
接口中的成员没有访问修饰符,默认是public类型的,而且不能手动添加任何访问修饰符。
实现接口时不需要override,实现接口的类中的方法的参数和返回值类型必须与接口中定义的类型完全一致。
接口命名一般以I开头,表示某种功能,实现某一接口表示具备了某一功能。
6、使用sealed关键字阻止派生类重写基类虚成员。
7、使用New关键字隐藏基类成员:当子类中需要添加的方法与基类中的方法名相同,使用new关键字隐藏基类方法,但如果想要强制访问基类方法,
则可使用强制类型转换,把子类强制转换成基类类型,例如:
1 //基类:Animal 2 public class Animal 3 { 4 private string _name; 5 private int _age; 6 7 public string Name 8 { 9 get { return _name; } 10 set { _name = value; } 11 } 12 13 public int Age 14 { 15 get { return _age; } 16 set 17 { 18 if (value < 0 || value > 10) 19 { 20 throw (new AggregateException("年龄必须在0~10岁之间!")); 21 } 22 _age = value; 23 } 24 } 25 26 public void Eat() 27 { 28 Console.WriteLine("动物的吃方法"); 29 } 30 } 31 32 //子类:羊 33 public class Sheep : Animal 34 { 35 public new void Eat() 36 { 37 Console.WriteLine("羊的吃方法"); 38 } 39 } 40 41 static void Main(string[] args) 42 { 43 Sheep sheep = new Sheep(); 44 sheep.Name = "Xi Yangyang"; 45 sheep.Age = 5; 46 sheep.Eat(); 47 ((Animal)sheep).Eat(); //子类强制转换成基类方法 48 49 Horse horse = new Horse(); 50 horse.Name = "Qian Li"; 51 horse.Age = 6; 52 53 Console.Read(); 54 }