一、抽象类的指针指向其派生的非抽象类的对象,从而体现多态性
1.1、实例代码://该实例代码来自,全国2009年10月自学考试C++程序设计试题 课程代码:04737 试题号:50
#include <iostream>
using namespace std;
#include <string.h>
class A
{
public:
virtual void GetA() = 0; //带有纯虚函数的类称为抽象类
};
class B : public A
{
private:
char str[32];
public:
void GetA(){cout<<"Class A"<<endl;};
const char * GetB(){return str;}
B(char * s){strcpy(str, s); }
};
void main()
{
A * a; //抽象类不能产生对象实例,但可以声明一个指向类A的指针
B b("Class B");
a = &b; //抽象类的指针指向其派生的非抽象类的对象,从而体现多态性
a->GetA(); cout<<b.GetB()<<endl;
}
1.2、多态是C++乃至面向对象中一个很重要的概念,也是大家学习中的难点,现在就我自己的理解写一些自己的学习心得:
多态性是指对于类的某个功能如果输入的信息不同,那么得到的结果就会不一样;具体来说,就是对同一条消息,被不同类型的对象接收将产生不同的行为。
在C++中,首先函数重载可以体现出多态性,也称为编译时的多态性,亦称静态联编。
所谓静态联编,就是在编译阶段即将主调函数和函数体之间进行连接的联编成为静态联编。那么,和静态联编相对应的就是动态联编,也叫运行时的多态性。其在运行阶段有系统自动选择需要调用的函数体---虚函数。
静态联编支持编译时多态,也称静态多态,它是通过运算符重载和函数重载实现的;动态联编支持运行时多态,也称动态多态,它是通过继承和虚函数实现的。如下例为静态联编实现:
Code:
claas Student
{
public:
void print()
{
cout<<"A student"<<endl;
}
};
class GStudent :public Student
{
public:
void print()
{
cout<<"A graduate"<<endl;
}
};
int main()
{
Student s1,*ps;
GStudent s2;
s1.print();
s2.print();
s2.Student ::print();
ps=&s1;
ps ->print(); //基类指针和基类成员发生关联
ps=&s2;
ps->print(); //希望调用s2的输出函数,但调用的却是对象s1的输出函数
return 0;
}
输出结果为:
Code:
A student
A graduate student
A student
A student
A student //在程序编译阶段,基类指针ps对print()的操作只能绑定到基类的print()上,导致输出了不期望的结果,而期望执行的是派生类的print()函数
虚函数定义: virtual 数据结构 函数名(形参表){函数体}
说明:虚函数即是在函数定义时加上的虚化关键词;
目的:为了能使系统最终实现多态联编。
a>如果一个函数未被声明为虚函数,那么该函数一定采用动态联编。
b>若一个函数声明为虚函数,该函数在调用时却不一定采用动态联编,即就是说讲一个函数声明为虚函数是采用动态联编的必要条件。
动态联编的条件:(1)基类和派生类中存在两个函数名相同、参数个数相同、参数类型相同、返回值相同的成员函数。
(2)基类中的同名成员函数被虚化。
(3)基类指针指向派生类对象或基类引用去引用派生类对象。
将上面代码中基类成员函数print()设为虚函数,并采用对象指针调用虚函数,便可实现动态联编。源代码如下:
Code:
claas Student
{
public:
virtual void print() //定义虚函数
{
cout<<"A student"<<endl;
}
};
class GStudent :public Student
{
public:
virtual void print() //此处关键字virtual可省略
{
cout<<"A graduate"<<endl;
}
};
int main()
{
Student s1,*ps;
GStudent s2;
s1.print();
s2.print();
s2.Student ::print();
ps=&s1;
ps ->print();
ps=&s2;
ps->print(); //对象指针调用虚函数,采用动态联编
return 0;
}
该程序运行结果如下:
Code:
A student
A graduate student
A student
A student
A graduate student //该程序将基类的print函数声明为虚函数,可以达到预期目的,即定义一个基类的对象指针,根据类型兼容规则,就可以指向不同的派生对象,同时调用不同派生类的虚函数,这就是动态联编的结果。
亦可将上例中基类的成员函数print()设为虚函数,采用对象引用调用函数,进而实现动态联编,源代码如下:
Code:
claas Student
{
public:
virtual void print() //定义虚函数
{
cout<<"A student"<<endl;
}
};
class GStudent :public Student
{
public:
virtual void print() //此处关键字virtual可省略
{
cout<<"A graduate"<<endl;
}
};
void main( Student &s ) //对象引用作参数
{
s.print(); //采用对象引用调用虚函数
}
int main()
{
Student s1;
GStudent s2;
fun(s1);
fun(s2);
return 0;
}
该程序运行的结果:
Code:
A student
A graduate student
综合以上运行结果表明:只要定义一个基类的对象指针或对象引用,就可以调用期望的虚函数。
二、模板
模板是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现真正的代码可重用性;模板可分为两类一类是函数模块,另一类是类模板;
函数模板的规则:
template <class/typename T>
返回类型 函数名(参数表)
{ /*函数体*/ }
如:template <class T> 换行 void max(T t1, T t2){ /*函数体*/ }
类模板的规则:
template <class/typename T>
class 类名
{
//类的定义
};