在进行MFC编程的过程中,在需要继承一个MFC类时想到其有许多虚函数,这些函数并没有一一去继承啊,印象中虚函数相当于Java的抽象类(实则不然),而继承抽象类的非抽象类时必须去实现所有的抽象函数。那么在C++中,虚函数应该是怎样的呢。伴随着这个疑惑,进行简单的编程验证。
疑惑起因:子类是否必须要去继承父类的虚函数?
代码:
class Father
{
public:
virtual void fun1(){cout <<"father"<<"\n";};
};
class Son : public Father
{
};
void main()
{
Son *son=new Son();
son->fun1();
return;
}
编译及执行没有错误,输出:father。因此,虚函数是可以不去实现的。
注:Java中abstract类的特性——
1)abstract类中可以有abstract方法,也可以有其他非abstract方法,甚至可以没有abstract方法,而非abstract类中不能有abstract方法;
2)abstract类不能用new创建该类的对象,其非abstract类的子类必须重写父类的abstract方法,其abstract类的子类则可以重写也可以继承父类的abstract方法;
3)abstract类虽不能使用new创建该类的对象,但是其可以成为其子类对象的向上转型对象,该对象可以调用子类重写的方法。
下面就C++的虚函数、纯虚函数、抽象类进行一个较为系统的总结:
1、虚函数
1)为何要有虚函数?如果不使用虚函数会发生什么?
class Father //基类
{
public:
void fun1(){cout <<"father"<<"\n";}//非虚函数
};
class Son : public Father //派生类
{
public:
void fun1(){cout <<"son"<<"\n";}//重写fun1
};
void main()
{
Father father; //Father对象
Father *pFather = &father; //Father对象的指针
Son son; //Son
Son *pSon = &son; //Son对象的指针
pFather->fun1(); //输出“father”
pSon->fun1(); //输出“son”
pFather = pSon; //基类指针指向派生类对象
pFather->fun1(); //输出“father”
return;
}
上述代码的输出已经在注释中说明,可见通过指针调用的成员函数只与指针类型有关,而与此刻指向的对象无关。下面将基类的fun1函数改为虚函数,如下:
class Father //基类
{
public:
virtual void fun1(){cout <<"father"<<"\n";}//虚函数
};
class Son : public Father //派生类
{
public:
void fun1(){cout <<"son"<<"\n";}//重写fun1
};
void main()
{
Father father; //Father对象
Father *pFather = &father; //Father对象的指针
Son son; //Son
Son *pSon = &son; //Son对象的指针
pFather->fun1(); //输出“father”
pSon->fun1(); //输出“son”
pFather = pSon; //基类指针指向派生类对象
pFather->fun1(); //输出“son”
return;
}
注:虚函数的特性——
1)虚函数无论被继承多少次,仍是虚函数,派生类对基类的虚函数进行重新定义时,virtual可写可不写(仍是虚函数),特别地如果派生类中定义的函数只是函数名和基类的虚函数名相同,而函数原型不同(参数个数及类型不同),则C++降之视为函数的重载(不默认是虚函数);
2)静态成员函数、构造函数、友元函数都不能声明为虚函数,因为它们依赖于对象。此外,全局函数、内联函数也不能声明为虚函数;
3)一般只将protected或public部分的成员函数声明为虚函数;
4)析构函数可以是虚函数;
5)只有通过基类指针或引用访问基类的虚函数时,才能获得运行时的多态性;
6)虚函数可以是另一个类中的友元函数。(此句未懂!)
7)派生类中可以将基类中的非虚函数重新定义为虚函数,可以通过该派生类指针或引用访问该派生类的这个虚函数,以获得运行时的多态性。(自己总结得)
2、纯虚函数
纯虚函数的形式:virtual 返回值类型 函数名(参数表)=0;也可以带函数体,即virtual 返回值类型 函数名(参数表)=0{函数体}
声明了虚函数的基类,只有通过基类指针或引用访问基类的虚函数时,才能获得运行时的多态性,同时该类仍然可以实例化。与之不同的是,
1)声明了纯虚函数的类则不能建立对象,只能声明指向该类的指针变量和引用变量(声明了纯虚函数的类称为抽象类,类中可以有其他非纯虚函数);
另外值得注意的是,
2)抽象类的派生类中若对“纯虚函数”没有重新定义,则这个派生类还是一个抽象类;
3)其非抽象类的派生类中,必须实现基类的所有纯虚函数。