多态性是指用一个名字定义不同的函数,这函数执行不同但又类似的操作,从而实现“一个接口,多种方法”。
多态性的实现与静态联编、动态联编有关。静态联编支持的多态性称为编译时的多态性,也称静态多态性,它是通过函数重载和运算符重载实现的。动态联编支持的多态性称为运行时的多态性,也称动态多态性,它是通过继承和虚函数实现的。
虚函数(virtual function)和多态性(Plymorphism)使得设计和实现易于扩展的系统成为可能。程序可以对层次中所有现有类的对象(基类对象)进行一般性处理。程序开发期间不存在的类可以用一般化程序稍作修改或不经修改即加进去,只要这些类属于一般处理的继承层次。程序中惟一要修改的部分是需要直接了解加进层次中的特定类的部分。
使用虚函数和多态性可简化源代码的长度。这种简化有助于程序的测试、调试和维护。
虚函数
假定一组形状类(如Circle、Triangle、Rectangle和Square等等)都是从基类Shape派生出来的。
在面向对象的程序设计中,我们可能要使每一个这样的类都能够计算自己的面积。尽管每个类都有它自己Area函数,但是计算每种形状的Area函数却是大不相同的。当需要计算面积时,不管它是什么形状,把它作为基类Shape的对象处理是再好不过的。然后,我们只需要简单地调用基类Shape的函数Area,并让程序动态地确定(即在执行时确定)使用哪个派生类的Area函数。
为了使这种行为可行,我们把基类中的函数Area声明为虚函数,然后在每个派生类中重新定义Area使之能够绘制合适的形状。虚函数的声明方法是在基类的函数原型前加上关键字virtual。
例如,基类Shape中可能出现:
virtual float Area() const; //虚函数,常量函数
上述原型声明函数Area是不取参数也返回float值的常量函数,而且是个虚函数。
注意:
为了指明某个成员函数具有多态性,用关键字virtual来标志其为虚函数。
如果虚函数在基类与子类中出现的仅仅是名字相同,而参数类型、个数不同或者返回类型不同,即使声明为virtual,也不会进行迟后联编。
一旦一个函数被声明为虚函数,即使重新定义类时没有声明虚函数,那么它从该点之后的继承层次结构中都是虚函数。
虽然函数在类层次结构的高层中声明为虚函数会使它在低层隐式地成为虚函数,但有些程序员为了提高程序的清晰性更喜欢在每一层中显式地声明这些虚函数。
没有定义虚函数的派生类简单地继承其直接基类的虚函数。
如果在基类中将函数Area声明为virtual,然后用基类指针或引用指明派生类对象并使用该指针调用Area函数(如pSharp->Area()),则程序会动态地(即在运行时)选择该派生类的Area函数,这称为动态关联
如果用名字和圆点成员选择运算符引用一个特定的对象来调用虚函数(如aCircle.Area()),则被调用虚函数是在编译时确定的(称为静态关联),调用的虚函数也就是为该特定对象的类定义(或继承该特定对象类)的函数。
纯虚函数和抽象类
如果将带有虚函数的类中的一个或者多个虚函数声明为纯虚函数,则该类就成为抽象类。纯虚函数是在声明时”初始化值”为0的函数,纯虚函数的一般形式:
virtual type func_name(参数表)=0。
例如:virtual float Area() const=0; //常量函数并且是纯虚函数
如果某个类是从一个带有纯虚函数的类派生出来的,并且没有在该派生类中提供该纯虚函数的定义,则该虚函数在派生类中仍然是纯虚函数,因而该派生类也是一个抽象类。
试图实例化一个抽象类对象(即包合一个或者多个纯虚函数的类)是一种语法错误。
虚函数和纯虚函数用法上有何区别?
有纯虚函数的类不能实例对象。
程序说明:
this关键字
this是一个关键字,它指向当前正在执行的类对象,使用this关键字告诉C++编译器到底要访问哪个变量。
虚函数与抽象类相关知识总结
2、虚函数必须是类的成员函数,不能将虚函数说明为全局(非成员)的函数,也不能说明为静态成员函数.
3、不能把友员函数(友员类)说明为虚函数,但虚函数可以是另一个类的友员(友员类).
4、析构函数可以是虚函数,但是构造函数不能是虚函数.
当在构造函数和析构函数中调用虚函数时,虚函数的虚特性将丢失,即不能实现动态联编.
5、一个函数被说明为虚函数,不管经历了多少次派生类层次,都保持其虚函数的特性.
6、当一个派生类中没有重新定义虚函数时,则使用其直接基类的虚函数版本.
7、纯虚函数:在基类中定义,任何派生类都必须定义自己的版本.
virtual 返回值类型 函数名(参数表)=0;
8、具有一个以上纯虚函数的类称为抽象类.
9、抽象类只能作为其他派生类的基类,不能建立自己的对象.
10、抽象类也不能作为参数类型,函数返回值类型或显示转换的类型.
11、可以声明抽象类的指针和引用.
{
virtual <类型><函数名>(<参数表>)=0;
…
};
的方法是在函数原型后加“=0”。如:
{
virtual <类型><函数名>(<参数表>)=0;
…
};
virtual 关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。例如,此方法可被任何继承它的类重写。
{
return x * y;
}
虚拟成员的实现可由派生类中的重写成员更改。
调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。
备注
抽象类具有以下特性:
4、实现由一个重写方法提供,此重写方法是非抽象类的成员。
抽象类必须为所有接口成员提供实现。
override 修饰符。
扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符。
override 方法提供从基类继承的成员的新实现。通过 override 声明重写的方法称为重写基方法。重写的基方法必须与 override 方法具有相同的签名。
接口就是纯抽象类,
委托当于函数指针,定义了委托就可以在不调用原方法名称的情况下调用那个方法 委托允许将方法作为参数进行传递。
enum 枚举名
{ 枚举值表 };
enum weekday
{ sun,mon,tue,wed,thu,fri,sat } a,b,c;
a=sun;
b=mon;
c=tue;
printf("%d,%d,%d",a,b,c);
枚举值是常量,不是变量 枚举元素本身由系统定义了一个表示序号的数值,从0 开始 只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。
namespace PC
{
partial class A { }
}
在 File2.cs 中:
namespace PC
{
partial class A { }
}
readonly 关键字readonly 关键字与 const 关键字不同
const 字段只能在该字段的声明中初始化。readonly 字段可以在声明或构造函数中初始化。
sealed 修饰符 密封类不能被继承
unsafe 关键字(不安全代码)任何涉及指针的操作所必需的
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。实现序列化
Object thisLock = new Object();
lock (thisLock)
{
// Critical code section
}
volatile 关键字表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假
定义一个范围,将在此范围之外释放一个或多个对象。
Font font2 = new Font("Arial", 10.0f);
using (font2)
{
// use font2
}