虚函数的声明virtual只能出现在类定义中函数原型的声明中,不能出现在类外函数体实现的地方
class base
{
virtual void get( ) ;
}
void base::get( )
{
}
virtual void base::get( ) //错误,virtual 关键字只用在类定义里的函数声明中,写函数体时不用。
{
}
小结:
(1)当成员函数做友元函数时,在类外定义时,不加friend
(2)静态成员,在类外定义时,不加static
(3)带默认参数值的成员函数在类内声明时指定,在类外定义时不能再指明参数的默认值
(4)内联函数必须把inline和函数体放在一起才有效
(5)常成员函数在类内类外都加const
实现动态联编的方法:
(1)首先要声明虚函数
(2)类之间是公有派生
(3)通过基类指针或引用调用虚函数
注意:
(1)通过对象名访问虚函数,只能实现静态联编,即利用对象名调用虚函数和调用一般函数没有区别
(2)通常将各类族中具有共性的成员函数声明为虚函数不具备多态性特征的函数不能声明为虚函数
比如,内联成员函数不能声明为虚函数静态成员函数不能声明为虚函数,友元函数不能声明为虚函数。
例class A
{
public:
virtual A( ) {}; //error C2633: “A”: “inline”是构造函数的唯一合法存储类
};
class B
{
public:
virtual static void funb( ) {}; //error C2216: “virtual”不能和“static”一起使用
};
int main( )
{ return 0;
}
(3)构造函数不能是虚函数
(4)析构函数经常被声明为虚函数
构造函数和析构函数内调用虚函数
采用静态联编,默认调用的虚函数是自己类中实现的虚函数,如果自己类中没有实现虚函数,则调用基类中的虚函数,而不是派生类中实现的虚函数
补充:成员函数调用虚函数 动态联编
虚析构函数
明确:
(1)如果主函数中不使用new delete 时,是否定义虚析构函数时没有差别
(2)派生类对象生存期结束时,先调用派生类的析构函数,再调用基类的析构函数
如果main函数中用new创建了派生类对象:
但析构函数不是虚函数
(1)如果基类中有析构函数
(2)且定义了一个指向基类的指针
(3)当程序用delete借助于基类指针删除派生类对象时,系统只执行基类的析构函数,而不执行派生类的析构函数。
例 普通析构函数在删除动态派生类对象的调用情况
#include<iostream>
using namespace std ;
class A
{ public:
~A(){ cout << "A::~A() is called.\n" ; }
} ;
class B : public A
{ public:
~B(){ cout << "B::~B() is called.\n" ; }
} ;
int main() {
A *Ap = new B ;
B *Bp2 = new B ;
cout << "delete first object:\n" ;
delete Ap;
cout << "delete second object:\n" ;
delete Bp2 ;
}
运行结果:
如果使用了虚析构函数:
用指针释放对象时,基类指针指向哪个层次的对象,则调用的就是哪个类的析构函数,进而释放掉对象空间
如果将基类的析构函数声明为虚函数,由该基类所派生的所有派生类的析构函数都会自动成为虚函数,即使各个类的析构函数名字不同。
虚析构函数在删除动态派生类对象的调用情况
#include<iostream>using namespace std ;
class A
{ public:
~A(){ cout << "A::~A() is called.\n" ; }
} ;
class B : public A
{ public:
~B(){ cout << "B::~B() is called.\n" ; }
} ;
int main()
{ A *Ap = new B ;
B *Bp2 = new B ;
cout << "delete first object:\n" ;
delete Ap;
cout << "delete second object:\n" ;
delete Bp2 ; }
运行结果:
补充:多继承和虚函数 单继承的扩展
在c++继承体系中,在派生类中可以重写不同基类中的虚函数。
#include <iostream> using namespace std;
class CBaseA{
public:
virtual void TestA()
{cout<<"CBaseATestA()"<<endl; }
};
class CBaseB{
public:
virtual void TestB()
{cout<<"CBaseB TestB()"<<endl; }
};
class CDerived:public CBaseA,public CBaseB{
public:
virtual void TestA(){
cout<<"CDerived TestA()"<<endl;
}
virtual void TestB(){
cout<<"CDerived TestB()"<<endl;
}
};
int main(){CDerived D;
CBaseA *pb1=&D;
CBaseB *pb2=&D;
pb1->TestA();
pb2->TestB();
return 0;
}
//运行结果:CDerived TestA()
CDerived TestB()