类的继承
class Rectangle : Shape{
}
类内每个函数要说明是public还是啥(静态构造方法不用)
通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。
class Shape
{
public void setWidth(int w)
{
width = w;
}
public void setHeight(int h)
{
height = h;
}
protected int width;
protected int height;
}
// 派生类
class Rectangle: Shape
{
public int getArea()
{
return (width * height);
}
}
base关键字
补充:base关键字在继承中的用法
- 主要!!!base用于在派生类中访问基类成员(即便被重写了);而this用于访问本类的成员
public class A
{
public virtual void Hello()
{
Console.WriteLine("Hello");
}
}
public class B : A
{
public override void Hello()
{
base.Hello(); //!!!base调用基类的方法,显示Hello!!!
Console.WriteLine("World");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b.Hello();
Console.ReadLine(); //运行结果是Hello World
}
}
- base调用基类构造函数
public class DerivedClass : BaseClass
{
// 该构造器调用 BaseClass.BaseClass()
public DerivedClass(): base()
{
}
// 该构造器调用 BaseClass.BaseClass(int i)
public DerivedClass(int i): base(i)
{
}
}
继承时构造方法的调用顺序为:子类静态、父类静态、父类构造、子类构造!!! (如果是孙子,则父类指的是所有祖宗!)
class Shape
{
protected int Width;
public int Heigth;
static Shape() {
Console.WriteLine("Shape父类静态构造方法");
}
public Shape(){
Console.WriteLine("Shape父类构造方法");
}
public Shape(int Width, int Heigth){
this.Width = Width;
this.Heigth = Heigth;
Console.WriteLine("Shape父类带参构造方法");
}
}
class Rectangle : Shape
{
static Rectangle(){
Console.WriteLine("Rect子类静态构造方法");
}
public Rectangle(){
Console.WriteLine("Rect子类实例构造方法");
}
public Rectangle(int Width, int Heigth){
Console.WriteLine("Rect子类实例带参构造方法");
}
}
Main函数里Rectangle b = new Rectangle(2,3);
则输出是
意思是public Rectangle(int Width, int Heigth)从public Shape()继承来;
但是如果
// 之前是public Rectangle(int Width, int Heigth):{}
public Rectangle(int Width, int Heigth):base(Width, Heigth){}
则输出为
意思是public Rectangle(int Width, int Heigth)从public Shape(int Width, int Heigth)继承来;
多重继承
多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。
C# 不支持多重继承。 但是,您可以使用接口来实现多重继承。下面的程序演示了这点:
using System;
namespace InheritanceApplication
{
// 基类 Shape
class Shape
{
public void setWidth(int w)
{
width = w;
}
public void setHeight(int h)
{
height = h;
}
protected int width;
protected int height;
}
// 接口!!!!!基类 PaintCost
public interface PaintCost
{
int getCost(int area); //在接口里声明getCost函数
}
// 派生类
class Rectangle : Shape, PaintCost
{
public int getArea()
{
return (width * height);
}
public int getCost(int area) //在派生类里定义了getCost函数
{
return area * 70;
}
}
class RectangleTester
{
static void Main(string[] args)
{
Rectangle Rect = new Rectangle();
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
Console.WriteLine("总面积: {0}", Rect.getArea());
Console.WriteLine("油漆总成本: ${0}" , Rect.getCost(area));
Console.ReadKey();
}
}
}
输出为:
总面积: 35
油漆总成本: $2450 //35*70
在接口里声明;在派生类里定义;
动态多态性
Abstract
Abstract
Abstract可以修饰 类,方法,属性索引
“标记为抽象”,“包含在抽象类中的成员”必须通过从抽象类派生的类来实现。(虚)
特点:
1、不能被实例化 即不能使用 new方法
2、抽象类可以包含抽象方法和抽象访问器
3、在方法或属性中声明
4、抽象方法是隐式的虚方法
注意:抽象类的每个方法都必须在派生类内实现!!!
比如如果SonClass继承自抽象类AbstractClass,但是没有对AbstractClass中的fun2方法进行定义,则:
public abstract class FunA //抽象类
{ public int NumberA = 100; //注意!与接口不同,可以有类变量
public int NumberB = 200;
public abstract void Swap(); //抽象方法
}
public class FunB: FunA
{
public override void Swap() //实现基类的SWAP方法
{
int temp = NumberA;
NumberA = NumberB;
NumberB = temp;
}
}
注意!与接口不同,抽象类可以有类变量
Virtual
应该和C++里的虚函数有点像:帮助复习:静态类型和动态类型,动态绑定,父类指针指向子类
在子类中用 override 重写父类中用 virtual 申明的虚方法时,实例化父类调用该方法,执行时调用的是子类中重写的方法;
如果子类中用 new 覆盖父类中用 virtual 申明的虚方法时,实例化父类调用该方法,执行时调用的是父类中的虚方法;
举个栗子🌰:
public class ParentClass
{
public virtual void ParVirMethod()
{
Console.WriteLine("父类的方法...");
}
}
public class ChildClass1 : ParentClass
{
public override void ParVirMethod()
{
Console.WriteLine("子类1的方法...");
}
}
public class ChildClass2 : ParentClass
{
public new void ParVirMethod()
{
Console.WriteLine("子类2的方法...");
}
}
执行:
ParentClass par = new ChildClass1(); //父类指针指向子类
par.ParVirMethod(); //结果:"子类1的方法",调用子类的方法,实现了多态
par = new ChildClass2();
par.ParVirMethod(); //结果:"父类的方法",调用父类的方法,没有实现多态
深究其原因,为何两者不同,是因为原理不同:
- override是重写,即将基类的方法在派生类里直接抹去重新写,故而调用的方法就是子类方法;
- new只是将基类的方法在派生类里隐藏起来,故而调用的仍旧是基类方法。
Abstract 和 Virtual的区别
virtual和abstract都是用来修饰父类的,通过覆盖父类的定义,让子类重新定义。
- 在基类中,virtual修饰的方法必须有实现(哪怕是仅仅添加一对大括号),而abstract修饰的方法一定不能实现。
- virtual可以被子类重写,而abstract必须被子类重写。
- 如果类成员被abstract修饰,则该类前必须添加abstract,因为只有抽象类才可以有抽象方法。
- 无法创建abstract类的实例,只能被继承无法实例化。
静态多态性
运算符重载
重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。
语法:
public static Box operator+ (Box b, Box c)
{
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
注意:static!公用,没必要创建多次