C++多态和虚函数学习笔记

1、从实现的角度看,多态可以划分为两种情况:编译期多态和运行时多态。

前者是在编译过程中,确定同名操作的具体操作对象,从而确定同名函数的具体实现;

后者是在程序运行过程中,动态确定具体的操作对象,从而确定同名函数的具体实现。

这种确定操作具体对象的过程成为联编或联合。联编就是将一个标识符和一个存储地址联系在一起的过程,是计算机程序自身彼此相关联的过程。

从联编进行的不同阶段,可以将联编分为静态联编和动态联编。

(1)静态联编是指联编工作在程序编译和连接阶段完成的联编过程。静态联编是程序编译之前进行的,也称为早期联编,前联编等。在有的多态类型中,程序在编译、连接的阶段就可以确定同名操作的具体操作对象。系统就可以根据类型匹配来确定某一个同名标识符调用的具体代码,如对于重载多态,强制多态、参数多态都可以通过静态联编来实现。

(2)动态联编就是指联编工作在程序运行阶段完成的联编过程。如果静态联编无法解决联编问题,则只能等到程序运行时再进行联编操作。例如,包含多态就是通过动态联编完成的。

2、虚函数是重载函数的另外一种表现形式。C++规定:基类的对象指针可以指向它公有派生的对象,但是当其指向共有派生类对象时,它只能访问从基类继承来的成员,而不鞥访问共有派生类中定义的成员。那么使用对象指针的目的就是为了表达动态的性质,即当指针指向不同对象时执行不同的操作。编译器采用的静态绑定的原则。此时就需要虚函数。

虚函数首先是基类中的成员函数,在这个成员函数前面加上关键字virtual,并在派生类中被重载。

对虚函数的定义有以下几点:

(1)由于虚函数使用的基础是赋值兼容规则,而赋值兼容规则成立的前提条件是派生类从其基类共有派生。因此,通过定义虚函数来使用多态性机制时,派生类必须从它的基类公有派生。

(2)必须首先在基类中定义虚函数。由于“基类”与“派生类”是相对的,因此,这项说明并不表明必须在类等级的最高层类中声明虚函数。在实际应用中,应该在类等级内需要具有动态多态性的几个层次中的最高类内首先声明为虚函数。

(3)在派生类对基类中声明的虚函数进行重新定义时,关键字virtual可以写也可以不写,但在容易引起混乱的情况下,最好在对派生类的虚函数进行重新定义时也加上关键字virtual。

(4)虽然使用对象名和点运算符也可以调用虚函数,但是这种调用是在编译时进行的静态联编,它没有充分利用虚函数的特性,只有通过基类指针访问虚函数时才能获得运行时的多态性。

(5)一个虚函数无论被公有继承多少次,它仍然保持虚函数的特性。

(6)虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态成员函数,因为虚函数调用要靠特定的对象来决定该哪个函数。

(7)内联函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的。即使虚函数在类的内部定义,编译时仍将其看作是非内联的。

(8)构造函数不能是虚函数,但是析构函数可以是虚函数,而且通常说明为虚函数。

3、虚析构函数,当派生类对象撤销时,一般先调用派生类的析构函数,然后再调用基类的析构函数。

#include<iostream>
using namespace std;
class base
{
public:
	~base()
	{
		cout << "调用基类的base的析构函数" << endl;
	}
};
class derived:public base
{
public:
	~derived()
	{
		cout <<" 调用派生类derived的析构函数" << endl;
	}
};
int  main()
{
	base *p;
//	p = &a;
	p = new derived;
	delete p;
}

运行结果表示,本程序只执行了基类base|的析构函数,而没有执行派生类derived的析构函数。原因是在撤销指针p所指的派生类的无名对象,而调用析构函数时,采用了静态联编的方式,只调用了基类base的析构函数。

如果采用动态联编方式,子啊用delete运算符撤销派生类的无名对象时,先调用派生类的析构函数,再调用基类的析构函数,可以将基类的析构函数声明为虚析构函数。

4、虚函数与重载函数的关系。在一个派生类中重新定义基类的虚函数是函数重载的另外一种形式,但它不同与一般的函数重载。普通的函数重载时,其函数的参数或参数类型必须有所不同,其返回类型也可以不同。但是在重载一个虚函数时,也就是说在派生类中重新定义虚函数时,要求,函数名,返回类型,参数个数,参数的类型和顺序与基类中的虚函数原型完全相同。

5、纯虚函数和抽象类。

有时,基类往往表示一种抽象的概念,在基类中将某一成员函数定义为虚函数,并不是类本身的要求,而是考虑到派生类的需要,在基类中预留了一个函数名,具体功能留给派生类根据需要去定义。

纯虚函数是在声明虚函数时被“初始化”为0的函数。

纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行重新定义。纯虚函数没有函数体,它最后的“=0”并不表示函数的返回值为0,它只是起形式上的作用,告诉编译系统“这是纯虚函数”。纯虚函数不具备函数的功能,不能被调用。

如果一个类至少有一个纯虚函数,那么就称该类为抽象类。定义抽象类的唯一目的就是用它作为基类去建立派生类抽象类作为一种基本类型提供给用户,用户在这个基础上根据自己的需要定义出功能各异的派生类,用用这些派生类去建立对象。对于抽象类的使用有以下几点规定:

(1)由于抽象类中至少包含一个没有定义功能的纯虚函数。因此,抽象类只能作为其他类的基类来使用,不能建立抽象类对象。

(2)不允许从具体类派生出抽象类。所谓具体类,就是不包含纯虚函数的普通类。

(3)抽象类不能用做函数的参数类型、函数的返回类型或显式转换的类型。

(4)可以声明指向抽象类的指针或引用,此指针可以指向它的派生类,进而实现多态性。

(5)如果派生类中没有定义纯虚函数的实现,而派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了。

抽象类是不能够实例化的,通常用于实现接口的定义。抽象类通常用作于其他类的父类,从抽象类派生的子类如果不是抽象类,则子类必须实现父类中的所有纯虚函数。

时间: 2024-11-03 04:24:06

C++多态和虚函数学习笔记的相关文章

PKU C++程序设计实习 学习笔记3 多态与虚函数

第六章 多态与虚函数 6.1 多态和虚函数的基本概念 引言 多态是面向对象程序设计里面非常重要的这个机制.它能很有效的提高程序的可扩充性. 有些程序设计语言有被对象继承的概念,但是没有多态的概念,那这样的程序设计语言只能被称作基于对象的程序设计语言,而不能称为面向对象的语言, 比方说visual basic. 虚函数 在类的定义中,前面有 virtual 关键字的成员函数就是虚函数. class base { <span style="color:#ff0000;">vir

GeekBand-secondweek-c++的多态和虚函数

多态与虚函数 13章的简单继承只是实现了对已有对象的实现的重定义和直接调用,但是向上映射导致的对象切割仍然是个缺陷: 1.延续13章的向上映射 简单继承中,派生类重定义了基类的成员函数,此时,向上映射的结果是很明显的,它使用了基类实现的函数版本,这显然并不是我们想要的效果:为什么会有这样的结果发生,我们先探讨几个问题: 函数调用绑定:函数调用确定目标函数体称为捆绑,编译期绑定称为早绑定,上面的问题就是早绑定引起的,因为编译器只知道基类对象的类型,调用函数也会绑定基类实现的函数版本,要解决这一问题

C++中的多态与虚函数的内部实现

1.什么是多态 多态性可以简单概括为“一个接口,多种方法”. 也就是说,向不同的对象发送同一个消息, 不同的对象在接收时会产生不同的行为(即方法).也就是说,每个对象可以用自己的方式去响应共同的消息.所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数.这是一种泛型技术,即用相同的代码实现不同的动作.这体现了面向对象编程的优越性. 多态分为两种: (1)编译时多态:主要通过函数的重载和运算符的重载来实现. (2)运行时多态:主要通过虚函数来实现. 2.几个相关概念 (1)覆盖.重

C++的多态与虚函数

多态性:对于同一消息,不同的对象由不同的响应方式 多态分为静态多态(编译时多态)和动态多态(运行时多态),动态多态通过虚函数来实现. 覆盖-->子类和父类中有同名同参数列表但是功能不同的函数叫做覆盖,在同一个类中有相同的是重复定义,不是覆盖. 虚函数的使用方法,如下: ①在基类中声明一个函数为虚函数,如: //基类vStudent class vStudent { public: vStudent(int,string); virtual void display();//虚函数,用来实现多态性

C++运算符重载为友元函数学习笔记

初探C++运算符重载学习笔记 在上面那篇博客中,写了将运算符重载为普通函数或类的成员函数这两种情况. 下面的两种情况发生,则我们需要将运算符重载为类的友元函数 <1>成员函数不能满足要求 <2>普通函数又不能访问类的私有成员时 举例说明: class Complex{ double real, imag; public: Complex(double r, double i):real(r), imag(i){ }; Complex operator+(double r); };

contiki-main.c 中的process系列函数学习笔记 &lt;contiki学习笔记之六&gt;

说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件. ------------------------------------------------------------------------------------------------------------------------------------- 根据上一个笔记里面添加的printf()语句的打印信息提示,hello world 打印是在执行了 1 autostart_

多态实现--虚函数与纯虚函数

多态实现--虚函数与纯虚函数 C++中实现多态是使用虚函数表的方法实现的. 那么具体怎么实现的呢? 举例说明 假设有这样一个多态场景: 有一个基类动物(animal类),动物里面又有两个派生类:猫(cat类)和狗(dog类).现在要求动物类有一个共同的方法:叫声(voice成员函数),但猫和狗叫声是不同的(即:它们的叫声实现方法不同). 那么代码怎么写呢? 多态的代码实现 #include <iostream> using namespace std; //1. 定义一个纯虚函数 class

C++ 多态与虚函数

1.多态的概念 由虚函数实现的动态多态性就是:同一类族中不同类的对象,对同一函数调用作出不同的响应. 先看下面这个简单的例子: #include<iostream> using std::cout; using std::endl; class A { public: void print(){cout << "I am A's print" << endl;} }; class B : public A { public: void print()

多态与虚函数

无论是在编译还是在运行时,c++都支持多态性.编译时的多态是通过重载函数和运算符实现的,而编译时的多态则是通过使用继承和虚函数实现的. 虚函数:是一个成员函数,该函数在基类声明,在派生类中重新定义.再基类中将成员函数声明前加关键字virtual,当继承包含虚函数的类时,派生类将重新定义虚函数. 虚函数实现了“一个接口,多种方法”.