下面总结了一些虚函数在笔试中的题型
-
构造函数可以调用虚函数吗?语法上通过吗?语义上可以通过吗?
可以,语法可以通过,但是不能实现多态,其语义是无法通过的。根据C++类初始化方式的定义,派生类在初始化时会调用父类的构造函数,但是若在调用父类的构造函数中出现了虚函数,是不会呈现多态的,因为此时派生类还没有完成初始化,所以是不能呈现多态的。如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。 -
构造函数可以调用虚函数吗?语法上通过吗?语义上可以通过吗?
可以。语法上可以通过。但是非常危险,不推荐使用。在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的
-
构造、析构函数可以是虚函数吗?
构造函数不可以是虚函数,因为构造时,对象还是一片未定型的处女地(感觉钱能老师文笔好叼),只有在完成构造完成后,对象才能成为一个名副其实的对象。
析构函数可以是虚函数,并且通常申明为虚函数。在类的继承中,如果有基类的指针指向派生类的对象,若基类的构造函数不是虚函数,则派生类的那部分无法完成析构,所以最好将基类的析构函数申明为虚函数,在删除基类指针的时候,首先会调用子类的析构函数。
同时还包括以下几个问题:
-
静态成员函数可以是虚函数吗?
静态成员函数不可以是虚函数,因为静态成员函数不接受对象的捆绑调用。不能捆绑调用也就失去了多态的必要条件,因为多态就是在运行时根据实际的对象,调用其相应得虚函数(滞后绑定),所以静态成员函数不可以是虚函数。
-
内联函数可以是虚函数吗?
内联函数不可以是虚函数,因为虚函数是滞后绑定,而内联函数是不能在运行中动态的确定其位置。即使虚函数在类的内部定义,编译器编译时仍然将她视为非内联。
最后强调一句,只有类的成员函数才能申明为虚函数。
-
例1:
</pre><pre class="cpp" name="code">#include<iostream>
using namespace std;
class B{
public:
virtualB* _fun(){
cout<< "In B" << endl;
returnthis;
}
};
class D :public B{
public:
D*_fun(){
cout<< "In D" << endl;
returnthis;
}
};
void fun(B *b){
B*bb;
bb=b->_fun();
}
int main(){
fun(&B());
fun(&D());
return0;
}
运行结果:
分析,在****之前是继承关系中的构造函数调用,在****之后是继承关系中的析构函数调用,从中可以得出,析构、构造函数都可以调用虚函数,但是析构函数中的虚函数是不能体现多态的,比如结果第一条输出(Base:fun)就是在基类中的。
关于虚函数的滞后绑定其余的不用多解释,下面介绍一个特例。
关于虚函数的滞后绑定,必须要求父类、子类的虚函数,返回类型、名称、行参一模一样。但是有个例外,那就是允许子类、父类的虚函数的返回值是各自的对象指针。
如下所示:
#include<iostream>
using namespace std;
class B{
public:
virtual B* _fun(){
cout << "In B" << endl;
return this;
}
};
class D :public B{
public:
D* _fun(){
cout << "In D" << endl;
return this;
}
};
void fun(B *b){
B *bb;
bb=b->_fun();
}
int main(){
fun(&B());
fun(&D());
return 0;
}
这个例外是可以理解的。因为父类、子类的虚函数返回各自的对象指针,更自然,更符合函数调用的一些习惯,但是只能这样书写才符合规范。在一般函数定义中,若函数至今仅仅是函数的返回值不同,则编译器会分不清调用哪个函数而报错,比如以下两个函数在一个源文件中会报错。
Void f(int)
Int f(int)