访问修饰符
1、 一个 访问修饰符 定义了一个类成员的范围和可见性
2、Public访问修饰符 允许一个类将其成员变量和成员函数暴露给其他的函数和对象。任何公有成员可以被外部的类访问。
3、Private访问修饰符 允许一个类将其成员变量和成员函数对其他的函数和对象进行隐藏。只有同一个类中的函数可以访问它的私有成员。
即使是类的实例也不能访问它的私有成员。
namespace ConsoleApplication14 //讨论public与private的区别-----暴露与隐藏 { class Rectangle { //成员变量 public double length; //公有变量length private double width; //私有变量width
} class Test { static void Main(string[] args) { Rectangle r = new Rectangle(); //实例化一个对象r r.length = 4.5; //这个语句是正确的 因为length是公有变量 可以被其他类访问 r.width = 3.5; //这个语句是错误的 因为width是私有变量 不能被类Test中的Main方法访问
} } }
class Rectangle //讨论private的特点-----可以被同一个类中的函数访问 { //成员变量 private double length; //私有变量 private double width; //私有变量 public void Acceptdetails() //必须设为公共函数 如果是私有函数 则类Test不能访问 可以通过该方法实现对私有变量的赋值 { Console.WriteLine("请输入长度:"); length = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("请输入宽度:"); width = Convert.ToDouble(Console.ReadLine()); } }//end class Rectangle class Test { static void Main(string[] args) { Rectangle r = new Rectangle(); r.Acceptdetails();//类Test访问Acceptdetails公有函数,Acceptdetails函数访问私有变量length 和 width,于是实现了在Main方法中间接访问一个类的私有变量 } }
4、Protected访问修饰符 允许子类访问它的基类的成员变量和成员函数,不允许其它无关类访问它的基类的成员变量和成员函数,这样有助于实现继承。
class Rectangle { protected double length; protected double width; //可以被子类(见继承)的函数访问 public double Area() { return length * width; } } class Test { static void Main(string[] args) { Rectangle r = new Rectangle(); //实例化一个对象r r.width = 3.5; //这个语句是错误的 因为width是保护变量 不能被非子类Test中的Main方法访问 r.Area(); //这个是正确的 } }
5、abstrac类(抽象类)
1、 C#中的abstract类不能被实例化,他只提供其他类的继承的接口,它的子类可以实例化
2、一个抽象类可以包含abstract方法,但是在子类中必须实现
3、一个抽象类的子类也可以是抽象类,此时只要实现部分abstract方法就行了
4、抽象类可以继承自非抽象类
5、抽象类不能声明为sealed(sealed 修饰符表示密封)
using System; abstract class MyAbs //抽象类 { public void NonAbMethod() { Console.WriteLine("Non-Abstract Method"); } } class MyClass : MyAbs //继承类MyAbs { } class MyClient { public static void Main() { //MyAbs mb = new MyAbs();//抽象类不能实例化 MyClass mc = new MyClass();//但是抽象类的子类可以实例化 mc.NonAbMethod(); } } 一个抽象类可以包含abstract方法,也可包含实例化方法,但继承类(非抽象)必须实现abstract方法 using System; abstract class MyAbs { public void NonAbMethod() { Console.WriteLine("Non-Abstract Method"); } public abstract void AbMethod(); // 抽象方法,只有声明,没有实现 } class MyClass : MyAbs//必须实现抽象方法 { public override void AbMethod() { Console.WriteLine("Abstarct method"); } } class MyClient { public static void Main() { MyClass mc = new MyClass(); mc.NonAbMethod(); mc.AbMethod(); } } 当然继承类也可以是抽象的 using System; abstract class MyAbs { public abstract void AbMethod1(); public abstract void AbMethod2(); } //抽象继承类不必全部实现抽象方法,部分实现便可 abstract class MyClass1 : MyAbs { public override void AbMethod1() { Console.WriteLine("Abstarct method #1"); } } class MyClass : MyClass1 { public override void AbMethod2() { Console.WriteLine("Abstarct method #2"); } } class MyClient { public static void Main() { MyClass mc = new MyClass(); mc.AbMethod1(); mc.AbMethod2(); } } 抽象类可以继承自非抽象类 using System; class MyClass1 { public void Method1() { Console.WriteLine("Method of a non-abstract class"); } } abstract class MyAbs : MyClass1 { public abstract void AbMethod1(); } class MyClass : MyAbs//实例类必须实现抽象方法 { public override void AbMethod1() { Console.WriteLine("Abstarct method #1 of MyClass"); } } class MyClient { public static void Main() { MyClass mc = new MyClass(); mc.Method1(); mc.AbMethod1(); } } 抽象类可以实现接口 using System; interface IInterface { void Method1(); } abstract class MyAbs : IInterface { public void Method1() { Console.WriteLine("Method implemented from the IInterface"); } } class MyClass : MyAbs { } class MyClient { public static void Main() { MyClass mc = new MyClass(); mc.Method1(); } } 最后需要注意的是抽象类不能声明为sealed,这两个语义是冲突的。抽象方法不必(也不能)声明为virtual,因为它缺省隐含就为virtual!
继承
1、继承在生活中的例子,牛继承食草动物,食草动物继承动物
2、继承符合的关系 : 父类更通用更抽象、子类更抽象更具体
3、继承背后的思想就是基于已存在的类来构造新的类,但从已存在类继承时,就重用了它的方法和成员,还可以添加新的方法和成员来定制新类来应对需求。
4、子类也叫派生类,父类也叫基类
5、继承是可以传递的。即:
6、C#继承有三种方式——公有继承(默认),私有继承,多重继承(通过接口实现)
<1>公有继承
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
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() //先增添了getArea方法 { return (width * height); } } class RectangleTester { static void Main(string[] args) { Rectangle Rect = new Rectangle();//实例化子类 Rect.setWidth(5); //子类继承了基类的setWidth方法 Rect.setHeight(7); // 打印对象的面积 Console.WriteLine("总面积: {0}", Rect.getArea()); Console.ReadKey(); } }
<2>私有继承
私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
私有继承的声明形式: class Foo : private Bar { public: void fun(); // ... };
<3>多重继承
多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。与单一继承相对,单一继承指一个类别只可以继承自一个父类。
C# 不支持多重继承。但是可以使用接口来实现多重继承。
什么是接口:接口就是一些方法特征的集合------接口是对抽象的抽象。
using System; namespace InheritanceApplication { 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); //声明函数 } // 派生类 class Rectangle : Shape, PaintCost//逗号 { public int getArea() { return (width * height); } public int getCost(int area) //实现接口中的函数 { 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(); } } }
多态
多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。
多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。
静态多态性
在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。C# 提供了两种技术来实现静态多态性。分别为:
- 函数重载
- 运算符重载
<1>函数重载
可以在同一个范围内对相同的函数名有多个定义。函数的定义必须彼此不同,可以是参数列表中的参数类型不同,也可以是参数个数不同。不能重载只有返回类型不同的函数声明。
using System; namespace PolymorphismApplication { class Printdata { void print(int i) { Console.WriteLine("Printing int: {0}", i ); } void print(double f) { Console.WriteLine("Printing float: {0}" , f); } void print(string s) { Console.WriteLine("Printing string: {0}", s); } static void Main(string[] args) { Printdata p = new Printdata(); // 调用 print 来打印整数 p.print(5); // 调用 print 来打印浮点数 p.print(500.263); // 调用 print 来打印字符串 p.print("Hello C++"); Console.ReadKey(); } } }
<2>运算符重载
可以重定义或重载 C# 中内置的运算符。因此,程序员也可以使用用户自定义类型的运算符。重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。
using System; namespace OperatorOvlApplication { class Box { private double length; // 长度 private double breadth; // 宽度 private double height; // 高度 public double getVolume() { return length * breadth * height; } public void setLength( double len ) { length = len; } public void setBreadth( double bre ) { breadth = bre; } public void setHeight( double hei ) { height = hei; } // 重载 + 运算符来把两个 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; } } class Tester { static void Main(string[] args) { Box Box1 = new Box(); // 声明 Box1,类型为 Box Box Box2 = new Box(); // 声明 Box2,类型为 Box Box Box3 = new Box(); // 声明 Box3,类型为 Box double volume = 0.0; // 体积 // Box1 详述 Box1.setLength(6.0); Box1.setBreadth(7.0); Box1.setHeight(5.0); // Box2 详述 Box2.setLength(12.0); Box2.setBreadth(13.0); Box2.setHeight(10.0); // Box1 的体积 volume = Box1.getVolume(); Console.WriteLine("Box1 的体积: {0}", volume); // Box2 的体积 volume = Box2.getVolume(); Console.WriteLine("Box2 的体积: {0}", volume); // 把两个对象相加 Box3 = Box1 + Box2; // Box3 的体积 volume = Box3.getVolume(); Console.WriteLine("Box3 的体积: {0}", volume); Console.ReadKey(); } } }
可重载和不可重载运算符
下表描述了 C# 中运算符重载的能力:
运算符 | 描述 |
---|---|
+, -, !, ~, ++, -- | 这些一元运算符只有一个操作数,且可以被重载。 |
+, -, *, /, % | 这些二元运算符带有两个操作数,且可以被重载。 |
==, !=, <, >, <=, >= | 这些比较运算符可以被重载。 |
&&, || | 这些条件逻辑运算符不能被直接重载。 |
+=, -=, *=, /=, %= | 这些赋值运算符不能被重载。 |
=, ., ?:, ->, new, is, sizeof, typeof | 这些运算符不能被重载。 |
动态多态性
C# 允许您使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。
请注意,下面是有关抽象类的一些规则:
- 不能创建一个抽象类的实例。
- 不能在一个抽象类外部声明一个抽象方法。
- 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。
using System; namespace PolymorphismApplication { abstract class Shape { public abstract int area(); } class Rectangle: Shape { private int length; private int width; public Rectangle( int a=0, int b=0) { length = a; width = b; } public override int area () { Console.WriteLine("Rectangle 类的面积:"); return (width * length); } } class RectangleTester { static void Main(string[] args) { Rectangle r = new Rectangle(10, 7); double a = r.area(); Console.WriteLine("面积: {0}",a); Console.ReadKey(); } } }
当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法。虚方法是使用关键字 virtual 声明的。虚方法可以在不同的继承类中有不同的实现。对虚方法的调用是在运行时发生的。
动态多态性是通过 抽象类 和 虚方法 实现的。
using System; namespace PolymorphismApplication { class Shape { protected int width, height; public Shape( int a=0, int b=0) { width = a; height = b; } public virtual int area() { Console.WriteLine("父类的面积:"); return 0; } } class Rectangle: Shape { public Rectangle( int a=0, int b=0): base(a, b) { } public override int area () { Console.WriteLine("Rectangle 类的面积:"); return (width * height); } } class Triangle: Shape { public Triangle(int a = 0, int b = 0): base(a, b) { } public override int area() { Console.WriteLine("Triangle 类的面积:"); return (width * height / 2); } } class Caller { public void CallArea(Shape sh) { int a; a = sh.area(); Console.WriteLine("面积: {0}", a); } } class Tester { static void Main(string[] args) { Caller c = new Caller(); Rectangle r = new Rectangle(10, 7); Triangle t = new Triangle(10, 5); c.CallArea(r); c.CallArea(t); Console.ReadKey(); } } }