【原创】C#零基础学习笔记007-面向对象的特性
其他路径:
CSDN: https://blog.csdn.net/wodehao0808
微信公众号:程序喵星人
更多资源和视频教程,QQ:1902686547
7 面向对象的特性
7.1 封装(字段和属性)
7.1.1 字段
字段表示类或结构中的对象或值。
字段使类和结构可以封装数据。
例:
public class Employee
{
private string _strName; // 字段
public string strDesc; // 字段
......
}
7.1.2 属性
属性是对现实世界中实体特征的抽象,它提供了对类或对象性质的访问。
C#中的属性更充分体现了对象的封装性:不直接操作类的数据内容,而是通过访问器进行访问,它借助于 get 和 set 对属性的值进行读写。
7.1.3 Example:封装
BankCount.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_30_1
{
public class BankCount
{
// 保证数据的安全性,对字段进行封装,所谓的封装,就是不能把字段暴露在外面直接访问或设置。
// 提供一种机制能够在字段进行赋值的时候进行检查,即属性。通过属性对这个字段进行访问或者设置。
// 设置 private 权限就不能在外部对这个类的字段进行直接的操作
private string _strCardid;
private double _dblBankMoney;
private string _strName;
// 一般我们在外部可以直接对属性进行操作,所以它的访问权限就是 public
public string Cardid // string类型必须跟_strCardid的类型相同
{
get // 表示我们在访问属性的时候,返回的值
{
return _strCardid;
}
set // 隐式参数value,表示即将赋值的数据
{
_strCardid = value;
}
}
public double BankMoney
{
get
{
return _dblBankMoney;
}
set
{
if ( value < 0 )
{
_dblBankMoney = 0;
}
else
{
_dblBankMoney = value;
}
}
}
public string Name
{
get
{
return _strName;
}
// 不提供set方法,表示这个属性是:只读;不能进行赋值操作
}
public BankCount( string p_strCardid, double p_dblBankMoney, string p_strName )
{
this._strCardid = p_strCardid;
this._dblBankMoney = p_dblBankMoney;
this._strName = p_strName;
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_30_1
{
class Program
{
static void Main(string[] args)
{
BankCount bcount = new BankCount( "1001", 100, "张三" );
Console.WriteLine( "取款金额:" );
double d = Convert.ToDouble( Console.ReadLine() );
bcount.BankMoney = bcount.BankMoney - d; // 通过 BankMoney 属性去修改 _dblBankMoney字段值
Console.WriteLine( "剩余余额:" + bcount.BankMoney );
Console.ReadKey(); // 避免一闪而过
}
}
}
7.2 继承
继承是面向对象语言的基本特征,是实现代码复用的手段。继承使得在原有的类基础之上,对原有的程序进行扩展,从而提高程序开发的速度,实现代码的复用。
创建相关的医生,学生,教师。
上面三个,都具有人的特征。
7.2.1 使用继承
7.2.2 继承的实现
7.2.3 base的使用
7.2.4 Example:继承
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_31_1
{
// 作为被继承的,那么称之为 基类,也称为 父类。
public class Person
{
private string _name;
private string _sex;
private int _age;
public string Name { get{ return _name; } set{ _name = value; } }
public string Sex { get{ return _sex; } set{ _sex = value; } }
public int Age
{
get
{
return _age;
}
set
{
_age = ( value < 0 ) ? 12 : value;
}
}
public Person( string p_name, string p_sex, int p_age )
{
_name = p_name;
_sex = p_sex;
_age = p_age;
}
public Person()
{
}
}
}
Doctor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_31_1
{
// Doctor可以称之为派生类,也称为子类
// Doctor 从 基类Person中继承了非private的属性
public class Doctor : Person
{
// 对基类属性的扩展,定义派生类(子类)特有的属性
private string _departName;
public string DepartName { get{ return _departName; } set{ _departName = value; } }
// base 表示父类的
public Doctor( string p_name, string p_sex, int p_age, string p_departName )
: base( p_name, p_sex, p_age ) // 调用父类的构造函数
{
DepartName = p_departName;
// this.Name = p_name;
// this.Sex = p_sex;
// this.Age = p_age;
}
public Doctor() : base()
{
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 继承
namespace Lesson_31_1
{
class Program
{
static void Main(string[] args)
{
Doctor d = new Doctor();
// 操作从基类继承来的属性的赋值和取值
d.Name = "张三";
d.Sex = "男";
d.Age = 16;
Console.WriteLine( "医生的姓名:" + d.Name );
Console.WriteLine( "医生的性别:" + d.Sex );
Console.WriteLine( "医生的年龄:" + d.Age );
Doctor d2 = new Doctor( "李四", "女", 26, "内科" );
Console.WriteLine( "医生的姓名:" + d2.Name );
Console.WriteLine( "医生的性别:" + d2.Sex );
Console.WriteLine( "医生的年龄:" + d2.Age );
Console.WriteLine( "医生的科室:" + d2.DepartName );
}
}
}
7.2.5 virtual 和 override 的使用
virtual 表示虚方法,可以在子类中被override重写。
7.2.6 Example:使用virtual和override的继承
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_31_1
{
// 作为被继承的,那么称之为 基类,也称为 父类。
public class Person
{
private string _name;
private string _sex;
private int _age;
public string Name { get{ return _name; } set{ _name = value; } }
public string Sex { get{ return _sex; } set{ _sex = value; } }
public int Age
{
get
{
return _age;
}
set
{
_age = ( value < 0 ) ? 12 : value;
}
}
public Person( string p_name, string p_sex, int p_age )
{
_name = p_name;
_sex = p_sex;
_age = p_age;
}
public Person()
{
}
// virtual 表示虚方法,可以被父类override重写
public virtual void showInfo()
{
Console.WriteLine( "姓名:" + Name + ", 年龄:" + Age + ", 性别:" + Sex );
}
}
}
Doctor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_31_1
{
// Doctor可以称之为派生类,也称为子类
// Doctor 从 基类Person中继承了非private的属性
public class Doctor : Person
{
// 对基类属性的扩展,定义派生类(子类)特有的属性
private string _departName;
public string DepartName { get{ return _departName; } set{ _departName = value; } }
// base 表示父类的
public Doctor( string p_name, string p_sex, int p_age, string p_departName )
: base( p_name, p_sex, p_age ) // 调用父类的构造函数
{
DepartName = p_departName;
// this.Name = p_name;
// this.Sex = p_sex;
// this.Age = p_age;
}
public Doctor() : base()
{
}
// new 表示对父类方法的覆盖
public new void showInfo()
{
Console.WriteLine( "姓名:" + Name + ", 年龄:" + Age + ", 性别:" + Sex + ", 科室:" + DepartName );
}
}
}
Student.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_31_1
{
public class Student : Person
{
private string _schoolName;
public string SchoolName
{
get { return _schoolName; }
set { _schoolName = value; }
}
public Student( string p_name, string p_sex, int p_age, string p_schoolName )
: base( p_name, p_sex, p_age )
{
SchoolName = p_schoolName;
}
// override 是针对父类已经定义好的虚方法(virtual)可以进行重写
public override void showInfo()
{
base.showInfo();
Console.WriteLine( "学校是:" + SchoolName );
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 继承
namespace Lesson_31_1
{
class Program
{
static void Main(string[] args)
{
Doctor d = new Doctor();
// 操作从基类继承来的属性的赋值和取值
d.Name = "张三";
d.Sex = "男";
d.Age = 16;
Console.WriteLine( "医生的姓名:" + d.Name );
Console.WriteLine( "医生的性别:" + d.Sex );
Console.WriteLine( "医生的年龄:" + d.Age );
Doctor d2 = new Doctor( "李四", "女", 26, "内科" );
Console.WriteLine( "医生的姓名:" + d2.Name );
Console.WriteLine( "医生的性别:" + d2.Sex );
Console.WriteLine( "医生的年龄:" + d2.Age );
Console.WriteLine( "医生的科室:" + d2.DepartName );
d2.showInfo();
Student stu = new Student( "王五", "男", 17, "中学" );
stu.showInfo();
}
}
}
7.3 多态
多态是指两个或多个属于不同类的对象,对同一个消息作出不同响应的能力。
7.3.1 抽象类
抽象类(abstract)
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的程序必须通过从抽象类派生的类来实现。
抽象类的特性
1.抽象类不能实例化。
2.抽象类可以包含抽象方法和抽象访问器。
3.不能用 sealed 修饰符修改抽象类,这意味着抽象类不能被继承。
4.从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实现。
7.3.1.1 Example: 多态:抽象类
Animal.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_33_1
{
// abstract 表示是一个抽象类
public abstract class Animal
{
private string _animalColor;
public string AnimalColor
{
get { return _animalColor; }
set { _animalColor = value; }
}
private double _weight;
public double Weight
{
get { return _weight; }
set { _weight = value; }
}
public Animal() { }
public Animal( string p_animalColor, double p_weight )
{
AnimalColor = _animalColor;
Weight = _weight;
}
public void show()
{
Console.WriteLine( "动物的颜色:" + AnimalColor + ", 动物的体重:" + Weight );
}
// 如果一个方法声明为抽象方法,那么方法就方法体的主体(即{}语块),只有方法的声明。
public abstract void showIt();
}
}
Pig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_33_1
{
public class Pig : Animal
{
public override void showIt()
{
Console.WriteLine( "这是 Pig 重写父类的抽象方法 showIt" );
}
}
}
Dog.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_33_1
{
// 子类(派生类)在继承抽象类的时候,必须实现抽象类中的抽象方法。
public class Dog : Animal
{
// 父类中定义的抽象方法,在子类中要进行重写。
public override void showIt()
{
Console.WriteLine( "这是 Dog 重写父类的抽象方法 showIt " );
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 多态:抽象类
namespace Lesson_33_1
{
class Program
{
static void Main(string[] args)
{
// Animal t_anm = new Animal(); // 抽象类不能被直接实例化。
Dog t_dog = new Dog();
t_dog.AnimalColor = "白色";
t_dog.Weight = 12.3;
t_dog.show();
t_dog.showIt();
// 多态:不同对象对同一个方法做出不同的实现,这种方式就称为面向对象中的多态行为。
Animal anm = new Dog(); // anm 指向实例对象 Dog
anm.showIt(); // 多态特性,这里调用的是 anm实际指向的对象 Dog中的showIt 方法
anm = new Pig(); // anm 指向实例对象 Pig
anm.showIt(); // 多态特性,这里调用的是 anm实际指向的对象 Pig中的showIt 方法
}
}
}
7.3.2 接口
接口(interface)定义了一个可由类和结构实现的协定。接口可以包括方法、属性、事件和索引器。接口不提供它所定义的成员的实现--它仅指定实现该接口的类或结构必须提供的成员。
应用案例:
为了实现跨行转账业务,定义了一个接口,该接口包含一个用于存取款的方法和一个返回余额的属性。
接口总结:
1.一个接口声明可以声明零个或多个成员。
2.接口的成员必须是方法、属性、事件或索引器。
3.接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型,也不能包含任何种类的静态成员。
4.所有接口成员都隐式的具有 public 访问属性。
5.接口成员声明中包含任何修饰符都属于编译时错误。具体来说,不能使用修饰符 abstract, public, protected, internal, private, virtual, override, static 来声明接口成员。
多重接口实现
7.3.2.1 Example: 多态:接口
IBank.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_34_1
{
// interface 表示这是一个接口
// 抽象类和接口的典型的区别,就是抽象类有字段和属性的定义,接口不能有字段和属性的定义。
// 抽象类只能单一继承,也就是一个雷只能继承一个抽象类。
// 接口可以多重继承,也就是一个类可以继承一个或者多个接口。
public interface IBank
{
double BankMoney { get; set; }
// 接口中,只有方法的声明,没有方法的实现;
// 接口中的方法是一个特殊的方法:
// 一个是方法的修饰符没有abstract关键字
// 一个是子类在实现接口时,它不必想抽象方法一样使用override
void zhuan( double p_dZhuan );
}
}
IUser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_34_1
{
public interface IUser
{
}
}
UserCard.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lesson_34_1
{
// 银行卡类
// 多重继承 接口
public class UserCard : IBank, IUser
{
///*
// 隐式实现
// 隐式实现接口的时候,那么在实现的方法或属性前不需要加所属的接口的名称,并且会加上publi访问权限。
private double _bankMoney;
public double BankMoney
{
get { return _bankMoney; }
set
{
_bankMoney = ( value < 0 ) ? 0 : value;
}
}
public void zhuan( double p_dZhuan )
{
BankMoney -= p_dZhuan;
}
//*/
/*
// 显示实现
// 显示实现接口的时候,那么在实现的方法或属性前面就会加上所属的接口的名称。
double IBank.BankMoney { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
void IBank.zhuan(double p_dZhuan)
{
throw new NotImplementedException();
}
*/
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 多态:接口
namespace Lesson_34_1
{
class Program
{
static void Main(string[] args)
{
UserCard uc = new UserCard();
uc.BankMoney = 200;
uc.zhuan(100);
Console.WriteLine( "卡上的余额:" + uc.BankMoney );
}
}
}