【Linux基础】用虚函数实现动态多态的机制

来源:互联网 发布:网络歌手排名 编辑:程序博客网 时间:2024/06/03 23:01
为了实现动态多态,编译器对每个包含虚函数的类创建一个虚函数地址表,并设置一个虚函数地址指针指向这个对象的虚函数地址表。使用基类指针对虚函数调用时,通过这个虚函数地址指针,在虚函数地址表中查找函数地址。
由于包含虚函数的类,有一个虚函数地址指针,与没有虚函数的类相比,含有虚函数类的对象所占用的存储空间要多一个指针所占用的内存。

01.jpg (26.63 KB, 下载次数: 0)

下载附件保存到相册设为封面

4 天前 上传

例7 含有虚函数类的对象所占用的存储空间。
#include <iostream.h>
class A
{
private:
int a;
public:
virtual void func(){}
};
class B : public A
{
private:
int b;
public:
virtual void func(){}
virtual void func1(){}
};
void main(void)
{
cout << "sizeof(A)=" << sizeof(A) << endl;
cout << "sizeof(B)=" << sizeof(B) << endl;
}

程序运行结果为:
sizeof(A)=8
sizeof(B)=12


每个含有虚函数类的对象都有一个虚函数地址指针,指向该类虚函数表,如果用基类的指针调用虚函数,在编译时,并不能确定这个指针的具体指向,而是在运行时,根据指针所指向的具体对象(基类的对象或其派生类的对象),虚函数地址指针才有一个确定的值,即相应类的这个虚函数的地址。从而实现动态多态。

虚析构函数
析构函数也可以定义为虚函数,如果基类的析构函数定义为虚析构函数,则派生类的析构函数就会自动成为虚析构函数。
如果基类的指针指向派生类对象,当用delete删除这个对象时,若析构函数不是虚函数,就要调用基类的析构函数,而不会调用派生类的析构函数。如果为基类和派生类的对象分配了动态内存,或者为派生类的对象成员分配了动态内存,这时释放的只是基类中动态分配的内存,而派生类中动态分配的内存未被释放,因此一般应将析构函数定义为虚析构函数。

例8 定义职员类CEmployee,数据成员有姓名(字符指针型数据)和年龄,由CEmployee类派生出教师类CTeacher,增加数据成员教学简历(字符指针型数据)。

#include <iostream.h>
#include <String.h>
class CEmployee
{
private:
char *name;
int age;
public:
CEmployee(char *n, int a);
virtual ~CEmployee();
};
CEmployee::CEmployee(char *n, int a)
{
name=new char[strlen(n)+ 1 ];
strcpy(name, n);
age = a;
}
CEmployee::~CEmployee()
{
cout << "Destruct CEmployee" << endl;
if(name)
{
delete []name;
}
}
class CTeacher : public CEmployee
{
private:
char *mainCourse;
public:
CTeacher(char *n, char *course, int a);
virtual ~CTeacher(); //由于基类已定义虚析构函数,此处也可不加virtual
};
CTeacher::CTeacher(char *n, char * course, int a) : CEmployee(n,a)
{
mainCourse = new char[strlen(course)+1];
strcpy(mainCourse, course);
}

CTeacher::~CTeacher()
{
cout << "Destruct CTeacher" << endl;
if(mainCourse)
delete []mainCourse;
}
void main(void)
{
CEmployee *p[3];
p[0] = new CEmployee("Name1", 20);
p[1] = new CTeacher("Name2","C for 2 years,C++ 3 years",26);
p[2] = new CTeacher("Name3","Data structure for 2 years,C++ 3 years",30);
for(int i=0; i<3; i++)
delete p;
}

程序运行结果为:
Destruct CEmployee
Destruct CTeacher
Destruct CEmployee
Destruct CTeacher
Destruct CEmployee

若不定义为虚析构函数,程序运行结果为:
由于未调用CTeacher类析构函数,导致成员mainCourse空间未被释放
Destruct CEmployee
Destruct CEmployee
Destruct CEmployee




纯虚函数与抽象类
纯虚函数是不必定义函数体的特殊虚函数,纯虚函数的声明格式为:
virtual 函数类型 函数名(参数表)= 0;
含有纯虚函数的类称为抽象类。抽象类常常用作派生类的基类。
如果派生类继承了抽象类的纯虚函数,却没有重新定义原型相同且带函数体的虚函数,或者派生类定义了基类所没有定义的纯虚函数,则派生类仍然是抽象类,在多层派生的过程中,如果到某个派生类为止,所有纯虚函数都已全部重新定义,则该派生类就成为非抽象类。
不能定义抽象类的对象,但可以声明抽象类的指针和引用。

例 9 将例题6中CShape类的函数Draw()声明为纯虚函数,其它类保持不变。

class CShape
{
private:
char Color[10];
public:
CShape(char *c)
{
strcpy(Color,c);
}
virtual void Draw()=0;
void PrintColor()
{
cout << Color << endl;
}
};
不能定义CShape类的对象,但可以定义CShape类的指针
void main()
{
CShape *ps[3];
CPoint p1(10,10), p2(100,100),p3(50,50);
CLine l(p1,p2,"Green");
CCircle c(p3, 20, "Black");
ps[1] = &l;
ps[2] = &c;
for(int i=1; i<3; i++)
ps->Draw();
}

程序运行结果为:
Draw a Line from (10, 10) to (100, 100) , with color Green
Draw a Circle at center (50, 50) with radius 20 and color Black

本人转载于唯C教育,【Linux基础】用虚函数实现动态多态的机制
http://www.weicedu.com/forum.php?mod=viewthread&tid=80&fromuid=4
(出处: http://www.weicedu.com/)
原创粉丝点击