现在的位置: 首页 > 综合 > 正文

C++:虚函数与抽象类 zz

2013年09月02日 ⁄ 综合 ⁄ 共 3619字 ⁄ 字号 评论关闭
自:http://zhangjunhd.blog.51cto.com/113473/57543
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<<endl;

}
 
LocalTime::LocalTime(int
h,int
m,int
s,string
z):Time(h,m,s),zone(z){}

 
void
LocalTime::show(){
  cout<<hour<<":"
<<min<<":"
<<sec<<"@"
<<zone<<endl;    

}
 
int
main(){
  Time t;
  LocalTime lt;
  Time *pt=&t;
  pt->show();
  pt=&lt;
  pt->show();
  system("PAUSE"
);

  return
EXIT_SUCCESS;

}
结果:
0:0:0
0:0:0
这里通过指针找到派生类,但无法调用派生类
show()
。如果使用虚函数。
将基类
Time
中的
show()
函数声明为虚函数,

其余不变。
class
Time{
  public
:

    Time(int
=0,int
=0,int
=0);

    virtual
void
show();

};
结果:
0:0:0
0:0:0@+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
中定义的函数)都自动成为虚函数,不管是否冠以virtual关键字。也就是说只要基类声明为virtual,其后一直为virtual。



 

4
】定义一个指向基类对象的指针变量,并使其指向同一类族(可能为子类)中的某个对象。通过该指针变量调用此函数,此时调用的就是指针变量指向的对象的同名函数。
 
1.3

声明虚函数的限制




1
】只能用
virtual
声明类的成员函数,使它成为虚函数,而不能将类外的普通函数声明为虚函数。
 

2
】一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非
virtual
的但与该虚函数具有相同参数(个数与类型)和函数返回值类型的同名函数。
 

3
】静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象。
 

4

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

5
】使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译器会为该类构造一个虚函数表
(virtual function tanle,vtable)
,它是一个指针数组,存放每个虚函数的入口地址。

6
】构造函数不能为虚函数,析构函数可以。


2.

虚析构函数



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)


,由于它常用作基类,通常称为抽象基类。凡是包含纯虚函数的类都是抽象类。
如果在派生类中没有对所有的纯虚函数进行定义,则此派生类仍然是抽象类,不能用来定义对象。
可以定义指向抽象类数据的指针变量。当派生类成为具体类后,就可以用这个指针指向派生类对象,然后通过该指针调用虚函数。

抱歉!评论已关闭.