在C++中,多态有两种,一种是函数重载,一种是虚函数。函数重载发生在编译的时候,它的函数参数是不一样的。而虚函数是发生在运行的时候,它的函数原型是一样的,依靠的是指针的指向。
结果似乎和我们想象的不一样,既然Graph类(图形类)的对象graph指针分别指向了Rectangle类(矩形类)对象,Triangle类(三角类)对象,以及Circle类(圆类)对象,那么就应该执行它们自己所对应成员函数showArea(),怎么结果会是Graph类(图形类)的对象graph里的成员函数呢?这好像和我们在C++之继承与派生(2)一节里所讲到的派生类成员覆盖了基类中使用相同名称的成员(派生类对象调用同名成员函数是来自于自己类中成员函数,而非基类中上的)有所不同啊,其实当基类对象指针指向公有派生类的对象时,它只能访问从基类继承下来的成员,而不能访问派生类中定义的成员。但是使用动态指针就是为了表达一种动态调用的性质即当前指针指向哪个对象,就调用那个对象对应类的成员函数。那要怎么来解决的,这时虚函数就体现出了它的作用。其实我们只需要对上一个示例代码中所有的类里出现的showArea()函数声明之前加一个关键字virtual:
向对象程序设计中的多态性是指向不同的对象发送同一个消息,不同对象对应同一消息产生不同行为。在程序中消息就是调用函数,不同的行为就是指不同的实现方法,即执行不同的函数体。也可以这样说就是实现了“一个接口,多种方法”。
从实现的角度来讲,多态可以分为两类:编译时的多态性和运行时的多态性。前者是通过静态联编来实现的,比如C++中通过函数的重载和运算符的重载。后者则是通过动态联编来实现的,在C++中运行时的多态性主要是通过虚函数来实现的,也正是今天我们要讲的主要内容。
1.不过在说虚函数之前,我想先介绍一个有关于基类与派生类对象之间的复制兼容关系的内容。它也是之后学习虚函数的基础。我们有时候会把整型数据赋值给双精度类型的变量。在赋值之前,先把整形数据转换为双精度的,在把它赋值给双精度类型的变量。这种不同类型数据之间的自动转换和赋值,称为赋值兼容。同样的,在基类和派生类之间也存在着赋值兼容关系,它是指需要基类对象的任何地方都可以使用公有派生类对象来代替。为什么只有公有继承的才可以呢,因为在公有继承中派生类保留了基类中除了构造和析构之外的所有成员,基类的公有或保护成员的访问权限都按原样保留下来,在派生类外可以调用基类的公有函数来访问基类的私有成员。因此基类能实现的功能,派生类也可以。
那么它们具体是如何体现的呢?(1)派生类对象直接向基类赋值,赋值效果,基类数据成员和派生类中数据成员的值相同;(2)派生类对象可以初始化基类对象引用;(3)派生类对象的地址可以赋给基类对象的指针;(4)函数形参是基类对象或基类对象的引用,在调用函数时,可以用派生类的对象作为实参;
在C++中,多态有两种,一种是函数重载,一种是虚函数。函数重载发生在编译的时候,它的函数参数是不一样的。而虚函数是发生在运行的时候,它的函数原型是一样的,依靠的是指针的指向。
结果似乎和我们想象的不一样,既然Graph类(图形类)的对象graph指针分别指向了Rectangle类(矩形类)对象,Triangle类(三角类)对象,以及Circle类(圆类)对象,那么就应该执行它们自己所对应成员函数showArea(),怎么结果会是Graph类(图形类)的对象graph里的成员函数呢?这好像和我们在C++之继承与派生(2)一节里所讲到的派生类成员覆盖了基类中使用相同名称的成员(派生类对象调用同名成员函数是来自于自己类中成员函数,而非基类中上的)有所不同啊,其实当基类对象指针指向公有派生类的对象时,它只能访问从基类继承下来的成员,而不能访问派生类中定义的成员。但是使用动态指针就是为了表达一种动态调用的性质即当前指针指向哪个对象,就调用那个对象对应类的成员函数。那要怎么来解决的,这时虚函数就体现出了它的作用。其实我们只需要对上一个示例代码中所有的类里出现的showArea()函数声明之前加一个关键字virtual:
向对象程序设计中的多态性是指向不同的对象发送同一个消息,不同对象对应同一消息产生不同行为。在程序中消息就是调用函数,不同的行为就是指不同的实现方法,即执行不同的函数体。也可以这样说就是实现了“一个接口,多种方法”。
从实现的角度来讲,多态可以分为两类:编译时的多态性和运行时的多态性。前者是通过静态联编来实现的,比如C++中通过函数的重载和运算符的重载。后者则是通过动态联编来实现的,在C++中运行时的多态性主要是通过虚函数来实现的,也正是今天我们要讲的主要内容。
1.不过在说虚函数之前,我想先介绍一个有关于基类与派生类对象之间的复制兼容关系的内容。它也是之后学习虚函数的基础。我们有时候会把整型数据赋值给双精度类型的变量。在赋值之前,先把整形数据转换为双精度的,在把它赋值给双精度类型的变量。这种不同类型数据之间的自动转换和赋值,称为赋值兼容。同样的,在基类和派生类之间也存在着赋值兼容关系,它是指需要基类对象的任何地方都可以使用公有派生类对象来代替。为什么只有公有继承的才可以呢,因为在公有继承中派生类保留了基类中除了构造和析构之外的所有成员,基类的公有或保护成员的访问权限都按原样保留下来,在派生类外可以调用基类的公有函数来访问基类的私有成员。因此基类能实现的功能,派生类也可以。
那么它们具体是如何体现的呢?(1)派生类对象直接向基类赋值,赋值效果,基类数据成员和派生类中数据成员的值相同;(2)派生类对象可以初始化基类对象引用;(3)派生类对象的地址可以赋给基类对象的指针;(4)函数形参是基类对象或基类对象的引用,在调用函数时,可以用派生类的对象作为实参;