韦庆清,崔如春,李 娅(佛山科学技术学院电子与信息工程学院,佛山528000)
虚机制在《面向对象程序设计C++》中的教学方法研究
韦庆清,崔如春,李娅
(佛山科学技术学院电子与信息工程学院,佛山528000)
虚机制是《面向对象程序设计C++》课程的重要学习内容。通过分析虚机制的基本特征,深入探讨虚机制的教学重点、教学难点、教学手段及教学方法,并根据该课程的教学特点,给出简易的应用程序实例,说明虚机制在面向对象程序设计中的实际应用,从而达到提高教学效果并顺利完成教学任务的目的。
教学方法;面向对象程序设计;虚机制
《面向对象程序设计C++》是大学本科计算机专业课程,“封装、继承及多态”三大基本特征是《面向对象程序设计C++》课程的重要学习内容,而贯穿这三大基本特征的学习则离不开其特有的虚机制对象,因此,从虚机制的基本教学内容出发,正确分析、探讨其基本教学特征;把握其教学重点和教学难点;设计、使用恰当的教学手段和教学方法;最后实施并完成好其教学目标是顺利完成该课程教学任务的重要保证。
在《面向对象程序设计C++》课程的课堂教学活动过程中,主要围绕着“封装、继承及多态”三大基本特征来展开相关知识内容的教学,而这三大特征的基本特点、基本原理和关键实现技术都离不开其特有的虚机制对象,常用的虚机制对象主要有虚函数、虚析构函数和虚基类等[1]。尽管这三个虚机制对象都用一个相同的关键字virtual来修饰,但其功能、作用却完全不同,在面向对象的程序设计过程中,虚函数主要用来实现运行时的多态性;虚析构函数主要用来实现动态联编,确保调用各析构函数使得在撤销动态分配空间的同时能得到正确的处理;而虚基类主要用来实现共享继承以消除多重继承引起的二义性。因此,在具体的教学活动过程中应分别设计、处理好各虚机制对象的实际教学。
课堂教学是整个课程教学中的重要环节,在这个环节中应该充分利用好课堂的45分钟时间,尽最大可能发挥好课堂教学的作用。因此,根据各不同的虚机制对象,应选择恰当的教学方法来完成其课堂教学任务。
2.1虚函数
虚函数,主要围绕其基本概念、功能及应用等三方面内容进行,重点讲解什么是虚函数,该函数有哪些基本特点、基本功能作用和实际应用,难点在于设计恰当的程序代码以说明虚函数在实际程序设计中的具体应用,并选择讲授法、讨论法和演示法作为主要教学方法。虚函数具体的教学过程设计如下:
虚函数(virtual function)就是在一个类中用保留字virtual来定义的非静态成员函数。基类的虚函数在其派生类中仍然是虚函数,并且一般需要在派生类中重定义。一个含有虚函数的类称为多态类,无论这些虚函数是继承下来的还是在派生类中新增加的[2]。在基类中说明虚函数的方法是:
virtual<函数返回类型><函数名>(<参数表>){…}
一个类的虚函数仅对派生类中重定义的函数起作用,而对其他函数没有影响。在基类中使用虚函数保证通过指向基类的指针调用基类的一个虚函数时,C++编译系统对该调用进行动态绑定,而使用普通函数则是静态绑定。
在派生类中重新定义虚函数时,要求函数原型必须与其在基类中的原型(函数返回类型、函数名、函数参数个数及其类型)完全一致。此外,还必须借助于基类指针才得以动态联编进而实现运行时的多态性。否则,虚函数将按静态联编方式调用[3]。
值得注意的是,函数重定义与函数重载不同,它们是两个不同的概念,具体定义时要注意其区别。以下实例程序代码说明虚函数在多态中的应用。
#include<iostream.h>
class BASE{
public:
virtual void fun1()
{cout<<"这是基类的虚函数fun1()."<<endl;}//在基类中定义一个虚函数fun1()
virtual void fun2()
{cout<<"这是基类的虚函数fun2()."<<endl;}//在基类中定义另一个虚函数fun2()
void fun3()
{cout<<"这是基类的普通函数fun3()."<<endl;}//在基类中定义一个普通函数fun3()
};
class DERIVED:public BASE{
public:
void fun1()
{cout<<"这是派生类的虚函数fun1()."<<endl;}//在派生类中重定义虚函数fun1()
void fun2(inta)
{cout<<"这是派生类的成员函数fun2()."<<endl;}//在派生类中重载fun2(),虚特性丢失
void fun3()
{cout<<"这是派生类的普通函数fun3()."<<endl;}//在派生类中定义普通函数fun3()
};
voidmain(){
BASE*p;DERIVED d;
p=&d;//定义基类指针指向派生类对象
p->fun1();//调用的是DERIVED::fun1(),动态联编
p->fun2();//调用的是BASE::fun2(),静态联编,虚特性丢失
p->fun3();//调用的是BASE::fun3(),静态联编}
程序运行结果如图1所示:
图1 虚函数在多态中的应用
由此可见,在面向对象的程序设计中,虚函数是实现运行时多态性不可缺少的前提条件。
2.2虚析构函数
在对虚析构函数所进行的教学活动设计过程中,应把该函数的基本概念和基本功能特征等内容作为教学重点讲解,而把设计一个程序实例作为教学难点,用来加以分析说明虚析构函数在类封装中的实际应用,并选择讲授法、对比法和演示法作为主要教学方法。虚析构函数具体的教学过程设计如下:
什么是虚析构函数?虚析构函数是指在析构函数前加上关键字virtual进行说明,则该析构函数称为虚析构函数。例如:
class A{
virtual~A(){…}//则为类A声明了一个虚析构函数
…
};
通常,习惯将基类的析构函数声明为虚析构函数。当基类的析构函数声明为虚析构函数时,无论指针指的是同类族中的哪一个类对象,系统会采用动态关联,调用相应的析构函数,对该对象执行清理工作,这样能更好避免内存泄漏现象[4]。以下程序代码说明虚析构函数的具体应用。
#include<iostream.h>
class A{
public:
virtual~A(){cout<<"这是类A的虚析构函数"<<endl;} //类A声明的虚析构函数
//~A(){cout<<"这是类A的析构函数"<<endl;}
};
class B:public A{
public:
B(){ptr=new int[20];}
virtual~B(){//类B声明的虚析构函数
cout<<"这是类B的虚析构函数"<<endl;
delete[]ptr;
}
//~B(){cout<<"这是类B的析构函数"<<endl;delete[]ptr;} private:int*ptr;
};
intmain(){
A*p=new B;
delete p;
return 0;
}
程序运行结果如图2所示:
图2 虚析构函数的应用
如果将上述程序代码中类A和类B所声明的虚析构函数改为析构函数,则程序运行结果仅显示:这是类A的虚析构函数。显然,在执行delete p;语句时并没有调用到类B的析构函数,因而引起内存泄漏。所以,通常是将基类的析构函数声明为虚析构函数,这样在用delete释放资源的时候,确保析构函数会被正确调用。
2.3虚基类
虚基类与前面所讲授的虚函数、虚析构函数相似。其具体的教学过程设计如下。
为什么要引入虚基类?因为在基于C++的面向对象程序设计的实际应用中,若在多重继承时没有作特殊声明,此时采用的是复制继承,会导致重复继承所带来的二义性问题。下面引入一个程序代码作分析说明。#include<iostream.h>
class BASE{public:int i;};
class BASE1:public BASE{public:int j;};
class BASE2:public BASE{public:int k;};
class DERIVED:public BASE1,public BASE2{public:int sum;};
void main(){
DERIVED obj;//声明一个派生类对象
//obj.i=3;//编译错误,编译程序无法确定使用i的哪一份副本
obj.j=5;//编译正确,使用从BASE1继承下来的j
obj.k=7;//编译正确,使用从BASE2继承下来的k}
通常,C++语言有两种方法解决这种二义性问题。第一种方法是采用作用域运算符“::”来解决,但这不是一种很好的解决途径;另一种方法是使用虚基类机制(Virtual Base Class)来解决。虚基类可以保证在任何派生类中只提供一个基类的副本,达到消除二义性问题的目的。
虚基类是当基类被继承时,在基类的继承访问控制关键字前面加上关键字virtual来定义的。声明虚基类的方法是:class派生类:virtual访问权限修饰符父类名{…};
现使用虚基类将上面程序代码修改如下:
#include<iostream.h>
class BASE{public:int i;};
class BASE1:virtual public BASE{public:int j;};
class BASE2:virtual public BASE{public:int k;};
class DERIVED:public BASE1,public BASE2{public:int sum;};
void main(){
DERIVED obj;//声明一个派生类对象
obj.i=3;//编译正确,
obj.j=5;//编译正确,使用从BASE1继承下来的j
obj.k=7;//编译正确,使用从BASE2继承下来的k
}
可见,普通基类与虚基类之间的唯一区别只有在派生类重复继承了某一基类时才表现出来,虚基类用于实现共享继承。该程序代码所实现的共享继承如图3所示,其相应的对象存储结构分配如图4所示:
图3 共享继承示意图
图4 对象存储结构分配图
(1)必须在最新派生出来的派生类的初始化列表中调用虚基类的构造函数,以初始化在虚基类中定义的数据成员;
(2)注意在调用各构造函数时,最先调用虚基类的构造函数,再调用其他构造函数;
(3)虚基类的构造函数仅调用一次[5]。
尽管在课堂上讲授了面向对象程序设计C++中虚机制的基本特征、功能作用等基本理论基础知识,但要学生在短时间内很好理解、掌握并能实际应用,还必须经过编程训练这一课外实践环节,从而延伸、反转课堂,以学生为主,逐步引导学生将其基本思想、理论和技术综合应用到实际程序开发设计中。在此,通过一个案例设计来分析说明虚机制在面向对象程序设计中的综合应用。
实例:将虚函数、虚析构函数和虚基类这三个虚机制对象综合应用到一个实际的面向对象程序设计中。
程序代码说明如下:
#include<iostream.h>
#include<string.h>
class Person{//定义基类
protected:char*name;
int age;
public:Person(char*nm,inta){
name=new char[strlen(nm)+1];
strcpy(name,nm);
age=a;
}
virtual~Person(){delete[]name;}//声明基类的虚析构函数
virtual void show(){cout<<name<<""<<age<<"";} //声明虚函数
};
class Student:virtual public Person{//声明由虚基类派生
protected:char*number;
int score;
public:
Student(char*nm,int a,char*no,int sc):Person(nm,a){
number=new char[strlen(no)+1];
strcpy(number,no);
score=sc;
}
virtual~Student(){delete[]number;}//声明派生类的虚析构函数
void show(){//虚函数重定义
Person::show();
cout<<number<<""<<score<<end l;
}
};
class Staff:virtual public Person{//声明由虚基类派生
protected:char*idnumber;
floatwage;
public:
Staff(char*nm,inta,char*id,floatw):Person(nm,a){
idnumber=new char[strlen(id)+1];
strcpy(idnumber,id);
wage=w;
}
virtual~Staff(){delete[]idnumber;}//声明派生的虚析构函数
void show(){//虚函数重定义
Person::show();
cout<<idnumber<<""<<wage<<endl;
}
};
class StaffStudent:public Staff,public Student{//多重继承
public:
StaffStudent(char*nm,inta,char*id,floatw,char*no,int sc):
Staff(nm,a,id,w),Student(nm,a,no,sc),Person(nm,a){}
void show(){//虚函数重定义
Person::show();
cout<<idnumber<<""<<wage<<""<<number<<""<<score<<""<<endl;
}
};
voidmain(){
Person*p;
Student st("李刚",19,"20151301",560);
Staff sf("王艳",29,"010",3500.9);
StaffStudent ss("邓军",25,"014",4500.5,"20151306",580);
p=&st;
p->show();//实现多态
p=&sf;
p->show();
p=&ss;
p->show();
}
程序运行结果如图5所示:
图5 虚机制的综合应用
综上所述,虚机制贯穿着《面向对象程序设计C++》教学过程的始终,而虚机制特征主要通过虚函数、虚析构函数和虚基类等这三个虚机制对象来具体实现。因此,在实际的教学活动过程中,应该设计并使用灵活、恰当的教学手段和教学方法来完成这三个虚机制对象的具体教学任务,以利于指导学生更好地理解、掌握虚机制对象的基本功能特征及其应用,并有效激发学生的学习兴趣,从而达到提高本课程教学质量、取得良好教学效果的目的。
[1]甘玲,邱劲.面向对象技术与Visual C++[M].北京:清华大学出版社,2006:4~7
[2]李师贤,李文军,周晓聪,等.面向对象程序设计基础(第二版)[M].北京:高等教育出版社,2011:316~318
[3]张冰.面向对象程序设计C++语言编程[M].北京:机械工业出版社,2008:154~155
[4]谭浩强.C++程序设计[M].北京:清华大学出版社,2004:407~408
[5]张海藩,牟永敏.面向对象程序设计实用教程(第二版)[M].北京:清华大学出版社,2007:165~167
Teaching Method;Object-Oriented Programming;VirtualMechanism
Research on the Method of VirtualMechanism in Object-Oriented Programm ing C++Course
WEIQing-qing,CUIRu-chun,LIYa
(School of Electronics and Information Engineering,Foshan University,Foshan 528000)
Virtualmechanism is the important study content in the Object-Oriented Programming C++course.Analyses the basic characteristics of virtualmechanism,and explores teaching emphasis,teaching difficulties,teachingmeans and teachingmethods of the virtualmechanism. Combiningwith the characteristics of the course learning,gives specific application examples to show the practical application of the virtualmechanism in object-oriented program design.Improves the teaching effectand completes the teaching task successfully.
1007-1423(2015)15-0021-06
10.3969/j.issn.1007-1423.2015.15.006
韦庆清(1966-),女,广西河池人,硕士,讲师,研究方向为计算机应用
崔如春(1965-),男,湖南沅江人,硕士,副教授,研究方向为计算机应用
李娅(1978-),女,湖北黄石河人,硕士,讲师,研究方向为智能优化算法
2015-04-21
2015-05-06