扣响C#之门笔记-第九章
9.1 继承的概念
继承:
基类(父类):不解释
派生类(子类):不解释
派生类中自动拥有了父类的定义的变量和函数,每个派生类也可以成为其他新派生类的父类;
9.2 由父类派生子类
1.继承的语法:

eg
class Animal //(1)定义父类 { public double weight; private double temperature; public Animal() { weight = 0; temperature = 0; } public void eat() { Console.WriteLine("eat"); } public void breathe() { Console.WriteLine("breathe"); } public void sleep() { Console.WriteLine("sleep"); } } class Mammal:Animal //(2)定义子类:继承于父类 { private string skins; public Mammal() { skins = "皮"; } public string Skins { set { skins = value; } get { return skins; } } public void run() { Console.WriteLine("run"); } public void scukle() { Console.WriteLine("scukle"); } } class Program { static void Main(string[] args) { Mammal best = new Mammal(); Console.WriteLine(best.weight); // (3)使用继承于父类中的属性 Console.WriteLine(best.Skins); // 使用新添加的属性 best.eat(); //使用继承于父类中方法 best.run();//使用子类添加的方法 Console.ReadKey(); } }
9.3 protected 成员
父类中private修饰的成员(类成默认修饰符是private),只能在类自己内部使用,不能再子类中使用;解决这个问题有两种方法:
(1)使用protected 修饰,protected 成员不能被类外部使用,但是在子类能使用(如果将成员修饰符换成public,但是这样会让类失去封装性);
(2)定义一个public的属性实现;
private成员:只有本类内能使用(本类的对象都不能使用)
class Animal { private double weight; } class dog:Animal { void print() { weight=30; //error,无法访问 } } class Program { static void Main(string[] args) { Animal a = new Animal(); a.weight = 30; //error,无法访问 } } }
protected 成员:只有本类(废话)和子类中能使用
class Animal { protected double weight; } class dog:Animal { void print() { weight=30; //protected 成员,子类可以访问 } } class Program { static void Main(string[] args) { Animal a = new Animal(); a.weight = 30; //error,protected 成员,外部无法访问 } } }
9.4 虚函数与重写
(1)虚函数就是用virtual修饰的函数,一般在基类上设计虚函数,在派生类中重写(Overwrite);
class Animal
{
private double temperature; //(1)虚函数
public virtual void eat()
{
Console.WriteLine("eat");
}
}
class dog : Animal
{
private double temperature;
public override void eat() //重写虚函数
{
Console.WriteLine("dog eat");
}
}
class Program
{
static void Main(string[] args)
{
dog g = new dog();
g.eat();
Console.ReadKey();
}
}
(2)重新(override)与重载:
重载:是指在同一个类中,有多个函数名相同,但是参数类型/个数不同的多个函数;重载发生在同一个类中;(系统根据调用的 实参数个数和类型自动匹配对应重载的函数)
重写:是指子类中定义了和父类同名的函数,并改写这个方法;重写发生在继承关系中;(系统根据对象的实际类型调用对应函数,如果对象是父类对象,就调用父类中方法,如果是是子类对象,则调用子类对象)
9.5 函数的隐藏
派生类可以使用new 关键修饰函数,从而隐藏基类中的同名函数;
new 关键字:用在函数前表示隐藏(覆盖)父类中的同名函数(可以不加new也可以覆盖,但是编译有告警)
class Animal { public void eat() { Console.WriteLine("eat"); } } class dog : Animal { public new void eat() //new 关键字,可以不加new也可以覆盖,但是编译有告警 { Console.WriteLine("dog eat"); } } class Program { static void Main(string[] args) { dog g = new dog(); g.eat(); Animal a = new Animal(); a.eat(); Console.ReadKey(); } }
6.6 Base关键字
利用关键字base,可以在子类中(只能在子类中)调用父类的重写的后者隐藏方法;
class Animal { public void eat() { Console.WriteLine("eat"); } } class dog : Animal { public new void eat() { base.eat(); //base关键字 } }
6.7抽象类和抽象函数
(1)抽象类:就是用就是用abstrct修饰的类
(a)抽象类不能实例化;
(b)抽象类和抽象函数,抽象属性没有什么必然关系,抽象类内部可以是抽象方法,也可以是一般法方法,或者都有都可以(但是有抽象方法的类一定是抽象类);
(c)如果一个非抽象类继承抽闲类,那么这个类,必须要重写(override)抽象父类中所有抽象方法,否则,这个类就必须还是抽象函数;
public abstract class Animal { private void eat() { Console.WriteLine(""); } public abstract void run(); public abstract void sleep(); } public class dog : Animal //错误,子类没有重写完父类所有抽象方法,这个类必须还是抽象函数 { public override void run(){} // }
(2)抽象函数:就是用就是用abstrct修饰的函数;(所有抽象成员的访问等级必须是public)
(a)抽象函数是一种特殊的虚函数,必须在抽闲类中定义;有抽象方法的类一定是抽象类;
(b)抽象函数定义时候只能有函数签名,不能有任何执方法体(包含{}都不能有);
public abstract class Animal { private void eat() { Console.WriteLine(""); } public abstract void run(){}; //错误,抽象方法不能有任何方法体 public abstract void sleep(); }
(C)抽象方法,抽象属性必须为public,否则编译出错;
abstract class Animal { private void eat() { Console.WriteLine("eat"); } abstract void run(); //错误抽象成员不能为私有的,只能为public public abstract void sleep(); }
(3)抽象属性:
(a)也可以定义抽象属性:抽象属性也不能有任何实现代码({}都不能有)
abstract class Animal { abstract public int Age { set; //不能有属性也不能有具体实现,({}都不能有) get; } }
(b)同样的,抽闲属性,也必须在继承类全部中用overridi,重写,否则这个类也必须为抽象类;
abstract class Animal { string name; abstract public int Age //抽象属性 { set; get; } } class dog : Animal { public override int Age //重写属性 { set { } get { return 3; } } }
(4)小结:
abstarct 可以修饰 方法,属性,不能修饰字段
1.抽象方法
(1)抽象方法就是用abstract 修饰的方法;
(2)抽象方法都必须是只有函数签名,不能有函数实现(包含{}都不能有);
public abstract void eat(){} //错误 1 “Test09.Animal.eat()”无法声明主体,因为它标记为 abstract
(3)抽象方法都public的,必须显示申明为public的(默认不加任何修饰符是private);
abstract void eat(); //错误 1 “Test09.Animal.eat()”: 虚拟成员或抽象成员不能是私有的
(4)抽象方法只能定义在抽象类中;(也就是说有一个抽象方法/属性的类必须是抽象类)
(5)抽象方法也不能是静态的;
public static abstract void eat(); //错误 1 静态成员“Test09.Animal.eat()”不能标记为 override、virtual 或 abstract
2.抽象属性:和抽象类好像,参考抽象方法即可;
(6)抽象属性方法就是用abstract 修饰的属性;
(7)抽象属性必须没有任何实现代码;
(8)抽象属性都public的,必须显示申明为public的(默认不加任何修饰符是private);
(9)抽抽象属性只能定义在抽象类中;(也就是说有一个抽象方法/属性的类必须是抽象类)
(5)抽象属性也不能是静态的,私有的;
3.抽象类:
(1)抽象类就是用abstract修饰的类,抽象类中可以有非抽象的成员(实体方法,字段等),抽象成员必须定义在抽象类内部;
abstract class Animal { string name; public abstract int Age { set; get; } public abstract void eat(); }
(2)抽象类不能为静态的或者密封的;
static abstract class Animal { } //error 错误 1 “Test10.Animal”: 抽象类不能是密封的或静态的
(3)抽象类不能实例化,如果一个类要继承抽象类,就需要实现重写(override)抽象类中所有(注意是所有)抽象成员,否则这个类还得是抽象类(因为有一个抽象成员的类就必须是抽象类;
abstract class Animal { string name; public abstract int Age { set; get; } public abstract void eat(); } class dog : Animal //error 没有重写(override)完抽象类中所有的抽象成员 { public override int Age { set { } get { return 3; } } }
9.8 密封类和密封函数
(1)密封类(用Sealed修饰的的类)是一种不能被继承的类
public sealed class Aniaml { int Age { get { return 0; } set { } } public int eat() { return 0; } } class dog : Aniaml //无法 继承sealed的类 { }
(2)密封方法(用Sealed修饰的的方法)是一种不能被重写的方法;
注意:sealed修饰方法/属性时,只能在override重写时候使用,意思是说禁止下次重写,父类总无法使用;
修饰类时候无此限制;
class dog : Aniaml { sealed override int Age { set { } get { return 0; } } //sealed 修饰方法时候,必须有override关键字 }
9.9 派生类的构造函数
1.构造函数过程
创建对象时,系统先先调用父类的构造函数,(初始化基类成员),然后再调用子类的构造函数(初始化子类成员);
是一个由基类向派生类逐步构建的过程;
删除对象是,先调用子类的析构函数(销毁子类成员),然后调用父类的析造函数(销毁父类中的成员);
是一个由派生类向父类逐步销毁的过程;
public class Aniaml { public int age; public int weighet; public Aniaml() { age = 0; weighet=0; Console.WriteLine("Aniaml的构造函数"); } ~Aniaml() { Console.WriteLine("销毁Aniaml"); } } class Dog : Aniaml { public Dog() { age = 1; weighet=1; Console.WriteLine("Dog的构造函数"); } ~Dog() { age = 1; weighet = 1; Console.WriteLine("销毁DOg"); } } class snoopy : Dog { public snoopy() { string name = "snoopy"; age = 3; weighet = 3; Console.WriteLine("snoopy的构造函数"); } ~snoopy() { Console.WriteLine("销毁snoopy"); } } class Program { static void Main(string[] args) { new snoopy(); //创建对象时候,从父类开始,依次向子类调用构造函数; Console.ReadKey(); //销毁对象时候,从子类析构函数开始,依次向父类调用函数析构; } }
2.带参数的构造函数
给给构造函数设置参数,在实例化对象时候,可以通过形参设置成员变量初始值,比较简单;
注意:
(1)如果人为类添加任何一个构造函数,系统就不会提供默认(无参数)的构造函数了,此时实例实话就不能用无参数的构造函数了;
(当然,如果人认为提供一个无参数的构造函数,当然才能能用)
class A { public int a; public A(int a) { Console.WriteLine(a); } } class Program { static void Main(string[] args) { A aa = new A();//error 系统已经无默认构造函数,无法调用 Console.WriteLine(aa.a); Console.ReadKey(); } }
(2)由于子类不能访问父类中的private成员,因此不能通过子类构造函数初始化父类的私有变量(可用用公共属性实现),但是可以显式调用父类的构造函数实现

一般不用,应该尽量保持不变,使用系统默认方式,让父类构造函数自己初始自己的私有属性;
9.2 万类之源 Object
(1)C#中的所有类都直接或者间接继承于Object类,如果定义一个类时候没有指定其父类,则编译器自动使他继承于Object;
【所有类都可以转为Object类型】
Object类成员含数:

(2)Tostring()是Object类中的虚函数,所有的类都继承了该函数,功能是返回与类相关的字符串
很多类都重写ToString函数,因此就能将很多类型自动转换为字符串;
int i = 3; string s=i.ToString();
实际上我们直接这样,系统或自动调用I的对应类型toString()方法,转为字符串;
Console.WriteLine("shu"+i);
(3)重写Tostring 方法:
class A { public override string ToString() //从写了父类object的ToString方法 { return "A的ToString方法"; } } class Program { static void Main(string[] args) { A a = new A(); Console.WriteLine(a); Console.ReadKey(); } }
浙公网安备 33010602011771号