文章目录
面向对象编程(OOP)有三个主要特性:
封装(Encapsulation):
封装是将数据(属性)和操作数据的方法(函数)绑定在一起,并隐藏内部实现细节的特性。通过封装,可以将对象的内部状态保护起来,只允许通过对象提供的公共接口进行操作,从而提高代码的安全性和可维护性。继承(Inheritance):
继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码的重用。子类可以扩展或修改父类的行为,形成一个层次结构。通过继承,可以简化代码并增加系统的可扩展性。多态(Polymorphism):
多态指的是不同的对象对相同的消息(方法调用)做出不同的响应。它允许一个接口以多种形式出现。例如,同一个方法名称在不同的对象中可以有不同的实现。多态提高了系统的灵活性和扩展性。
这三个特性是面向对象编程的核心,帮助开发者设计更为模块化、易维护和可扩展的软件系统。
一、继承的基本使用
继承的概念:
允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码的重用。
继承的特点:
继承的顺序不可逆,继承的下级拥有上一级的属性和方法。
为什么使用继承?
解答:最主要的方法是实现代码的复用,举例:有一个猫类和狗类,但是两者都有大量的属性和方法是重复的,所以这个时候可以建一个动物类,让猫类和狗类继承动物类,减少代码的使用。
应继承的步骤和使用要点:
- 1、抽象的公共部分放到一个特定的类中(父类)
- 2、其他子类继承父类,就能拥有父类的属性和方法。
- 3、根据子类的需要,写单独的特征和方法。
具体实现方法:
在子类的后面使用冒号:父类
class Dog : Animal
{
//赛跑
public void Race()
{
Console.WriteLine("下面我给大家表演《狗狗精彩百米跨栏》,请大家鼓掌啊:>");
}
}
二、继承的关键字
1、this关键字
this关键字可以访问父类的成员。
2、base关键字
调用父类的构造函数、调用父类的属性和方法。base
关键字可以在方法,构造函数和属性的访问器中使用,但是不可以在结构、成员声名中使用。
错误的使用:
class Dog : Animal
{
public Dog(string name, string color, string kind, string favorite)
: base(name, color, kind)//调用父类的构造方法
{
this.Favorite = favorite;
}
base.Introduce();//在成员声名中使用是无效的
}
正确的使用:
父类:
class Animal
{
//无参数构造函数
public Animal() { }
//3个参数的构造方法
public Animal(string name, string color, string kind)
{
this.Color = color;
this.Name = name;
this.Kind = kind;
}
public string Name { get; set; }//名字
public string Color { get; set; }//颜色
public string Kind { get; set; }//种类
public string Favorite { get; set; }//喜好
//自我介绍
public void Introduce()
{
string info = string.Format("我是漂亮的{0},我的名字叫{1},身穿{2}的衣服,我爱吃{3}!", Kind, Name, Color, Favorite);
Console.WriteLine(info);
}
}
子类:
class Dog : Animal
{
public Dog(string name, string color, string kind, string favorite)
: base(name, color, kind)//调用父类的构造函数
{
this.Favorite = favorite;
}
//赛跑
public void Race()
{
base.Introduce();//调用父类的方法
Console.WriteLine("下面我给大家表演《狗狗精彩百米跨栏》,请大家鼓掌啊:>");
}
}
如上使用this也可以,但是最好要用base,更好阅读性,base先调用父类的构造函数,然后再调用子类的构造函数,因为创建子类实例的时候会先创建子类所继承的父类。
3、Protected关键字
如果父类中的某个成员函数只允许其子类访问,那么使用Protected关键字
// 定义子类 Dog 继承自 Animal
public class Dog : Animal
{
// 子类构造函数
public Dog(string name) : base(name)
{
}
// 子类的方法,用于调用父类的 protected 方法
public void DogSpeak()
{
// 可以直接访问父类的 protected 成员
Speak();
}
}
4、子类调用父类的构造函数的总结:
问题:如果去掉父类的构造函数,并且子类不使用base那么会如何?
隐式调用:如果其他子类的构造函数没有使用base指明调用的父类的那个构造函数时,子类会默认调用父类的无参数构造函数。
显示调用:如果父类没有无参数的构造函数,子类的构造函数必须指明调用父类的那个构造函数。
总之父类要么写一个无参数的默认的构造函数,要么子类指定,不然会报错。
三、继承的特性
继承的传递性:
A是B的父类,B是C的父类,那么C具有A的特性。
继承的单根性:
一个类只能有一个父类。
四、父类和子类的相互转换
给cat和dog分别添加have的方法:
class Cat : Animal
{
public Cat(string name, string color, string kind, string favorite)
: base(name, color, kind)
{
this.Favorite = favorite;
}
//吃饭
public void Have()
{
Console.WriteLine("我们要吃香喷喷的烤鱼啦!");
}
}
class Dog : Animal
{
public Dog(string name, string color, string kind, string favorite)
: base(name, color, kind)
{
this.Favorite = favorite;
}
//吃饭
public void Have()
{
Console.WriteLine("我们要吃香喷喷的排骨啦!");
}
}
static void Main(string[] args)
{
//创建一只狗和一只猫
Cat objCat = new Cat("球球儿", "黄色", "小花猫", "小鱼");
Dog objDog = new Dog("棒棒", "黑色", "小黑狗", "排骨");
//将子类对象添加的父类集合
List<Animal> list = new List<Animal>();
list.Add(objCat);
list.Add(objDog);
//取出子类对象
foreach (Animal obj in list)
{
if (obj is Cat)
((Cat)obj).Have();
else if (obj is Dog)
((Dog)obj).Have();
}
Console.ReadLine();
}
由于父类不能直接调用子类的方法,所以这种很麻烦,所以我们引出下面的抽象类和抽象方法。