C++的虚函数与抽象类
副标题#e#
1.虚函数
1.1虚函数的浸染
虚函数的浸染是答允在派生类中从头界说与基 类同名的函数,而且可以通过基类指针或引用来会见基类和派生类中的同名函数。
class Time{
public:
Time(int=0,int=0,int=0);
void show();
protected:
int hour;
int min;
int sec;
};
class LocalTime:public Time{
public:
LocalTime(int=0,int=0,int=0,string="+8");
void show();
protected:
string zone;
};
Time::Time(int h,int m,int s):hour (h),min(m),sec(s){}
void Time::show(){
cout<<hour<<":"<<min<<":"<<sec& lt;<endl;
}
LocalTime::LocalTime(int h,int m,int s,string z):Time (h,m,s),zone(z){}
void LocalTime::show(){
cout<<hour<<":"<<min<<":"<<sec& lt;<"@"<<zone<<endl;
}
int main(){
Time t;
LocalTime lt;
Time *pt=&t;
pt->show();
pt=<
pt->show();
system("PAUSE");
return EXIT_SUCCESS;
}
功效:
0:0:0
0:0:0
#p#副标题#e#
这里 通过指针找到派生类,但无法挪用派生类show()。假如利用虚函数。
将基类Time中的 show()函数声明为虚函数, 其余稳定。
class Time{
public:
Time(int=0,int=0,int=0);
virtual void show();
…
};
功效:
0:0:0
0:0:[email protected]+8
原来,基类指针是指向基 类工具的,假如用它指向派生类工具,则举办指针范例转换,将派生类工具的指针先转换为 基类指针,所以基类指针指向的是派生类工具中的基类部门。在措施修改前,是无法通过基 类指针去挪用派生类工具中的成员函数的。
虚函数打破这一限制,在派生类的基类部 分中,派生类的虚函数代替了基类本来的虚函数,因此在利用基类指针指向派生类工具后, 挪用虚函数时就挪用了派生类的虚函数。
1.2虚函数的利用要领
【1】在基类 用virtual声明成员函数为虚函数。这样就可以在派生类中从头界说此函数,为它赋予新的功 能,并能利便地被挪用。
【2】在派生类中从头界说此函数,要求函数名、函数(返 回)范例、函数参数个数和范例与基函数的虚函数沟通。假如在派生类中没有对基类的虚函 数重界说,则派生类简朴地担任直接基类的虚函数。
有一种环境破例,在这种环境下 派生类与基类的成员函数返回范例差异,但仍起到虚函数的浸染。即基类虚函数返回一个基 类指针或基类引用,而子类的虚函数返回一个子类的指针或子类的引用。
class Base{
public:
virtual Base *fun(){
cout<<"Base's fun()."<<endl;
return this;
}
};
class Derived:public Base{
public:
virtual Derived *fun(){
cout<<"Derived's fun ()."<<endl;
return this;
}
};
void test (Base &x){
Base *b;
b=x.fun();
}
int main(){
Base b;
Derived d;
test(b);
test(d);
system ("PAUSE");
return EXIT_SUCCESS;
}
功效:
Base's fun().
Derived's fun().
【3】C++规 定,当一个成员函数被声明为虚函数后,其派生类中的同名函数(切合2中界说的函数)都自 动成为虚函数。
【4】界说一个指向基类工具的指针变量,并使其指向同一类族中的 某个工具。通过该指针变量挪用此函数,此时挪用的就是指针变量指向的工具的同名函数。
1.3声明虚函数的限制
【1】只能用virtual声明类的成员函数,使它成为虚函 数,而不能将类外的普通函数声明为虚函数。
【2】一个成员函数被声明为虚函数后 ,在同一类族中的类就不能再界说一个非virtual的但与该虚函数具有沟通参数(个数与范例 )和函数返回值范例的同名函数。
【3】静态成员函数不能是虚函数,因为静态成员 函数不受限于某个工具。
【4】inline函数不能是虚函数,因为inline函数是不能在 运行中动态确定其位置的。纵然虚函数在类的内部界说,编译时,仍将其视为非inline的。
【5】利用虚函数,系统要有必然的空间开销。当一个类带有虚函数时,编译器会为 该类结构一个虚函数表(virtual function tanle,vtable),它是一个指针数组,存放每个虚 函数的进口地点。
2.虚析构函数
#p#分页标题#e#
class Time{
public:
Time(int=0,int=0,int=0);
~Time(){
cout<<"Time destructor"<<endl;
}
protected:
int hour;
int min;
int sec;
};
class LocalTime:public Time{
public:
LocalTime(int=0,int=0,int=0,string="+8");
~LocalTime(){
cout<<"LocalTime destructor"<<endl;
}
protected:
string zone;
};
Time::Time(int h,int m,int s):hour(h),min(m),sec(s){}
LocalTime::LocalTime(int h,int m,int s,string z):Time(h,m,s),zone(z){}
int main(){
Time *p=new LocalTime;//指向派生类
delete p;
system ("PAUSE");
return EXIT_SUCCESS;
}
功效:
Time destructor
从功效可以看出,执行的照旧基类的析构函数,而措施的本 意是但愿执行派生类的析构函数。此时将基类的析构函数声明为虚析构函数,
virtual ~Time(){
cout<<"Time destructor"<<endl;
}
功效:
LocalTime destructor
Time destructor
假如将基类的析构函数声明为虚函数,由 该基类所派生的所有派生类的析构函数也自动成为虚函数。
把基类的析构函数声明为 虚函数的长处是,假如措施中delete一个工具,而delete运算符的操纵工具是指向派生类对 象的基类指针,则系统会挪用相应类的析构函数。
结构函数不能声明为虚函数。
3.纯虚函数
virtual void show()=0;//纯虚函数
这里将show()声明 为纯虚函数(pure virtual function)。纯虚函数是在声明虚函数时被“初始化” 为0的虚函数。
声明纯虚函数的一般形式为,
virtual 函数范例 函数名(参数 列表)=0;
纯虚函数没有函数体;最后的“=0”并不代表函数返回值为0, 它只起形式上的浸染,汇报编译器“这是纯虚函数”;这个一个声明语句,最后 有分号。
声明纯虚函数是汇报编译器,“在这里声明白一个虚函数,留待派生 类中界说”。在派生类中对此函数提供了界说后,它才气具备函数的成果,可以被挪用 。
纯虚函数的浸染是在基类中为其派生类保存了一个函数的名字,以便派生类按照需 要对它举办界说。
假如在一个类中声明白纯虚函数,而在其派生类中没有对该函数定 义,则该函数在派生类中仍为纯虚函数。
4.抽象类
将不消来界说工具而只作 为一种根基范例用作担任的类,称为抽象类(abstract class),由于它常用作基类,凡是称 为抽象基类。每每包括纯虚函数的类都是抽象类。
假如在派生类中没有对所有的纯虚 函数举办界说,则此派生类仍然是抽象类,不能用来界说工具。
可以界说指向抽象类 数据的指针变量。当派生类成为详细类后,就可以用这个指针指向派生类工具,然后通过该 指针挪用虚函数。