封装
C#中类的访问级别分为public,protected,private,Internal和protected Internal.Internal的作用是限制访问该类只能在当前程序集中,就是只能在当前dll库或当前exe程序中,意味着其他的程序集不能从该类派生子类来实现。C#和C++的封装区别还在于,C++使用public:来限定后面的语句都是在同一个作用域内,而C#的限定符只对当前语句有效,需要为每个成员和方法都声明作用域,如果不使用显示声明,就使用默认的作用域。
class默认为Internal作用域,成员和方法默认是Private作用域
//public表示该类可以在任何地方被派生或调用
//Internal表示该类只能在本程序集中被派生或调用
//protected表示只能被子类派生或在子类中被调用
//默认是Internal作用域,该类只能在本程序集中使用
public class MyClass
{
//成员变量默认都是private,只能在本类使用,派生类或外部都不可以访问
int age = 30;
string name = "zhangsan";
//成员方法默认也是private,不能被外部访问,需要显示添加public才能访问
public void Print()
{
Console.WriteLine("name = {0}, age = {1}", name, age);
}
//声明static表示静态方法,和C++类似,可以使用类作用域访问
//因为是public,所以可以在外部使用MyClass.sPrint()访问
static public void sPrint()
{
Console.WriteLine("This is static function!");
}
}
//类的创建都使用new方法,这点和C++有很大区别
MyClass obj = new MyClass();
obj.Print();
//访问类的静态public方法
MyClass.sPrint();
继承
多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。与单一继承相对,单一继承指一个类别只可以继承自一个父类。
C# 不支持多重继承。但是,您可以使用接口来实现多重继承。
C#派生类必须实现和基类一致的构造函数。
比如基类有base(int,int)这样的构造函数,那么在派生类中也必须要实现同样的subclass(int,int)构造函数。
//接口1
public interface PaintCost
{
int getCost(int area);
}
//接口2
public interface CalArea
{
int getArea();
}
//基类实现
class Shape
{
//基类构造函数
protected Shape(int w, int h)
{
width = w;
height = h;
}
//基类方法1
public int GetWidth()
{
return width;
}
//基类方法2
public int GetHeight()
{
return height;
}
//基类成员,声明为protected可以被子类使用
protected int width;
protected int height;
}
// 派生类
class Rectangle : Shape, PaintCost, CalArea
{
//子类构造函数,调用了基类的构造函数
//必须实现和基类一致的构造函数,比如基类有base(int,int)这样的构造函数
//那么在派生类中也必须要实现同样的subclass(int,int)构造函数
public Rectangle(int w, int h) : base(w, h)
{
}
//实现接口1的方法
public int getCost(int area)
{
return area * (width + height) ;
}
//实现接口2的方法
public int getArea()
{
return (width * height);
}
}
//创建派生类的对象
Rectangle rect = new Rectangle(20, 30);
//打印方法输出
Console.WriteLine("Cost={0}, Area={1}", rect.getCost(100), rect.getArea());
//分别获取基类引用,接口1和接口2的引用
//这里类似C++中的子类到基类的类型转换:
//C++: base* b = subclass;
PaintCost cost = rect;
CalArea cal = rect;
Shape sh = rect;
//从接口1打印
Console.WriteLine("PaintCost.Cost={0}", cost.getCost(100));
//从接口2打印
Console.WriteLine("CalArea.Area={0}", cal.getArea());
//从基类打印成员
Console.WriteLine("Shape.width={0}, Shape.height={1}", sh.GetWidth(), sh.GetHeight());
//也可以使用as关键字来进行类型转换
Shape sh2 = rect as Shape;
//基类到派生类的转换:
//C++:subclass* sub = dynamic_cast<base>(base);
//if (sub != nullptr) 需要做一下判断是否转换成功
Rectangle rect2 = sh as Rectangle;
if (rect2 != null)
{
//需要做一下判断,转换失败rect2为空,但不会抛出异常
}
多态
多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。
静态多态性
C# 提供了两种技术来实现静态多态性。分别为:函数重载和运算符重载。
C#的函数重载和C++类似,运算符重载将在下一节专门说明。
动态多态性
C#动态多态性是通过抽象类和虚方法实现的。
抽象类使用关键字abstract来声明。
虚方法使用关键字virtual来声明。
派生类中使用override来重载基类的抽象方法和虚方法。
1、抽象类
您不能创建一个抽象类的实例。 您不能在一个抽象类外部声明一个抽象方法。 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。
//抽象类abstract
abstract class Shape
{
//抽象方法abstract
public abstract int area();
}
class Rectangle : Shape
{
//实现抽象方法override
public override int area()
{
throw new NotImplementedException();
}
}
2、虚方法
当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法。虚方法是使用关键字 virtual 声明的。虚方法可以在不同的继承类中有不同的实现。对虚方法的调用是在运行时发生的。
class Shape
{
//基类虚方法,有自己的实现
public virtual int area()
{
Console.WriteLine("父类的面积:");
return 0;
}
}
class Rectangle : Shape
{
//派生类重载虚方法,实现自己的订制化功能
public override int area()
{
Console.WriteLine("Rectangle 类的面积:");
return (width * height);
}
}
运算符重载
class Box
{
// 重载 + 运算符来把两个 Box 对象相加
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;
}
}
Box Box1 = new Box(); // 声明 Box1,类型为 Box
Box Box2 = new Box(); // 声明 Box2,类型为 Box
Box Box3 = new Box(); // 声明 Box3,类型为 Box
// ...
// 把两个对象相加
Box3 = Box1 + Box2;
//特别说明:
//这里Box3可以不用new Box()操作
//如果有new操作,那么上面的操作其实是赋值操作,将Box1+Box2产生的Box对象拷贝给Box3
//如果没有new操作,那么Box3实际上是Box1+Box3产生的Box对象的引用类型
//前者是新的对象产生,会花费更多时间和空间,后者更快,但是共享内存空间,如果该内存空间不会
//被其他地方使用,那么没有任何问题,如果有被其他使用,就可能引发其他问题。
//常见的运算符重载
public static Box operator +(Box b, Box c);
public static bool operator ==(Box lhs, Box rhs);
public static bool operator !=(Box lhs, Box rhs);
public static bool operator <(Box lhs, Box rhs);
public static bool operator >(Box lhs, Box rhs);
public static bool operator <=(Box lhs, Box rhs);
public static bool operator >=(Box lhs, Box rhs);
public override string ToString();
接口
抽象类在某种程度上与接口类似,但是,它们大多只是用在当只有少数方法由基类声明由派生类实现时。接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的。
**C#仅支持单一继承,但可以实现多个接口。 **
接口也可以被继承,实现类必须实现继承链上的所有接口方法:
//接口1
interface IParentInterface
{
void ParentInterfaceMethod();
}
//接口2继承接口1
interface IMyInterface : IParentInterface
{
void MethodToImplement();
}
//实现类继承接口2,因此必须实现接口1和接口2的所有方法
class InterfaceImplementer : IMyInterface
{
//实现接口1的方法
public void ParentInterfaceMethod()
{
Console.WriteLine("ParentInterfaceMethod() called.");
}
//实现接口2的方法
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
}