【C#】封装 继承 多态(面向对象的三大特性)
继承
使用继承,可以把对象的相同属性和方法写到父类中,然后在子类中继承父类中的属性和方法,这样便于封装,也简写了代码。不同的属性和方法在各自的子类中单独声明。
可以通过查看类图,来查看程序中父类和子类,继承关系有箭头指向。
所有的类都继承了object类,当我们定义一个类的时候,如果没有定义继承关系,那么就默认为继承object类
#region 继承
Person p = new Person();
Teacher t = new Teacher();
t.Name = "老牛最邪恶";
t.Age = 50;
t.Gender = '女';
t.Sayhi();
//t.Show();
Console.ReadKey();
Student stu = new Student();
//使用继承,可以把学生和老师的相同点继承于人类,可以删除相同代码,
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
//使用继承,可以把学生和老师的相同点继承于人类,删除相同的代码,便于封装
public class Person
{
string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
public void Show()
{
Console.WriteLine("我是人,别害怕");
}
}
public class Teacher:Person //使用冒号继承,冒号后面的就是父类的名字
{
public void Sayhi()
{
Console.WriteLine("我是老师,别害怕,我叫{0},我今年{1}岁,我是{2}生",this.Name,this.Age,this.Gender);
}
}
public class Student:Person //学生类继承人类
{
public void Sayhello()
{
Console.WriteLine("我是学生,别害怕");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
显示调用父类的构造函数
子类中如果有参数构造函数,默认的调用父类中的无参数构造函数,这时容易报错。
如果要调用父类的有参数构造函数,需要加关键字base。
public class Student:Person
{
//加上base,调用父类的构造函数
public Student(string name, int age, char gender, string id):base(name,gender,age)
{
this._id =id;
}
string _id;
public string Id
{
get { return _id; }
set { _id = value; }
}
public void SayHello()
{
Console.WriteLine("我叫{0},今年{1}岁了,是{2}同学",this.Name,this.Age,this.Gender);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
修饰符
protected,受保护的,不允许其他非子类访问,只允许本身和子类访问。
这里是继承的传递性和单根性。
Internal 当前程序集内可以访问。
里式转换
#region 里氏转换的四种情况
//第一种情况
Student stu = new Student();
Person p = stu;
p.Show();
Console.ReadKey();
//第二种情况
Person p = new Teacher();
Teacher t = (Teacher)p; //如果 new的时候 new的是 子类,那么再转换这个子类的时候可以
t.Sayhi();
Console.ReadKey();
//第三种情况
Person p = new Teacher();//如果new的是子类,转换的时候 转的另一个子类,报异常
Student stu = (Student)p;
stu.SayHello();
Console.ReadKey();
//第四种情况
Person p = new Person();
Student stu = (Student)p;//父类对象不能直接转换子类
stu.SayHello();
Console.ReadKey();
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
#region as可以直接转换
Person p1 = new Person();
Teacher t1 = p1 as Teacher;
//as也是转换,但是转换不了的,不报异常,返回来的是null
//is转换,返回的是bool值,true就是可以转换,false就是不能转换
t1.Say();//未将对象引用设置到对象的实例
Console.ReadKey();
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
#region is 的使用
Person p = new Teacher();
if (p is Teacher)
{
Teacher t = (Teacher)p;
t.Say();
}
Console.ReadKey();
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
多态
多态就是对象可以表现多个类型的能力
子类可以与父类方法名相同的方法
签名不同(重载);
签名相同(隐藏基类方法)
子类可以重写父类方法
虚方法
重写方法
重写基类方法一样可以调用基类方法
父类实现多态
重写和虚方法
子类的方法名和父类相同的时候,会出现一条绿线,解决方法有两个
一、直接在子类方法的修饰符后面加new就可解决(无论怎么加new都不影响使用)。
二、可以在父类的方法修饰符后面加virtual(虚方法),在子类中重写父类的方法,加上一个override(重写)调用父类的方法,但是这样就更换了方法里面的内容。
#region 子类重写父类
Person p = new Person();
p.Show();
Teacher t = new Teacher();
t.Name = "张三";
t.Age = 90;
t.Gender = '男';
t.Show();
Console.ReadKey();
}
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
public virtual void Show()//虚方法 ----
{
Console.WriteLine("我是人别害怕");
}
public void Say()
{
Console.WriteLine("hello");
}
}
public class Teacher : Person
{
public override void Show()//重写
{
Console.WriteLine("我是老师");
}
}
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
虚方法和重写的特点:
方法不能用static修饰
方法重写必须与父类的签名一致
virtual不能与private一起使用,不能使用私有的修饰符
虚方法总结
虚方法用virtual修饰
在子类中通过override关键字来重写
常见的虚方法:ToString()Equals
#region 常见的虚方法
Person p = new Person();
Console.WriteLine(p);
Console.ReadKey();
}
public class Person
{
public override string ToString()//string可以有返回值
{
return "夏普爱国和四";
}
}
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
抽象类实现多态
抽象方法和抽象类
抽象类与抽象方法使用abstract修饰
注意:
抽象方法没有方法体
抽象成员只能存在于抽象类中
抽象类可以有非抽象成员
抽象类的派生类必须实现抽象方法体
抽象类只能用作基类,无法实例化
父类是抽象类,子类继承这个类的时候,必须把抽象类中的抽象方法重写。
#region 抽象方法
Pig pig = new Pig();
pig.Shout();
Console.ReadKey();
}
public abstract class Animal
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
public abstract void Shout();
public void SayHello()
{
Console.WriteLine("哈哈哈");
}
}
public class Pig : Animal
{
public override void Shout()
{
Console.WriteLine("哼哼叫");
}
}
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
重写和重载
override是重写,overload是重载
重载是方法的名称相同,参数和参数类型不同,进行多次重载以适应不同的需要,重载是免息那个过程的概念
Override 是进行基类中函数的重写,override 是面向对象的概念
重写和重载是不一样的概念。
虚方法和抽象方法的对比
用接口实现多态
接口的实现
#region 接口的实现
IFly ifly = new Teacher();//又是多态的体现形式
ifly.IFly();
Console.ReadKey();
}
}
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
public void Show()
{
Console.WriteLine("{0}岁的{1}是最纯洁的{2}老师", _age, _name, _gender);
}
}
public class Teacher : Person, IFly
{
public void Say()
{
Console.WriteLine("hellow,我是老师");
}
public void IFly()
{
Console.WriteLine("我会飞");
}
}
public class Student : IFly
{
public void SayHello()
{
Console.WriteLine("我是学生");
}
public void IFly()
{
Console.WriteLine("我会飞");
}
}
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
接口的定义
internal interface IFly
{
void IFly();
}
- 1
- 2
- 3
- 4
接口和类的异同
C#中接口和类的异同:
不同点:
不能直接实例化接口
接口不包含方法的实现
接口可以多继承,类只能单继承
类定义可在不同的源文件之间进行拆分
相同点:
接口 类和结构都可以从多个接口继承
接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员
接口和类可以包含事件、索引器、方法和属性
类之间不支持多重继承,接口直接支持。
类对接口叫做实现,不叫继承,类是父类,接口是能力,可以有多个能力,但是不能有多个父类
抽象类和接口的异同
封装
也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。
简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
索引器
#region 索引器
List<int> listInt = new List<int>();
//listInt[0]
MyList myList = new MyList();
myList.Add(1);
myList.Add(2);
myList.Add(3);
string st = myList.ToString();
Console.WriteLine(st);
Console.ReadKey();
}
}
public class MyList
{
List<int> list = new List<int>();
public int this[int index]
{
get { return list[index]; }
set { list[index] = value; }
}
public void Add(int item)
{
list.Add(item);
}
public override string ToString()
{
string str = "";
foreach (int item in list)
{
str += item;
}
return str;
}
}
#endregion
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
感谢阅读~
文章来源: blog.csdn.net,作者:张艳伟_Laura,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/Laura__zhang/article/details/111057706
- 点赞
- 收藏
- 关注作者
评论(0)