c++之虚函数

在同一类中不能定义两个名字相同、参数个数和类型都相同的函数,否则,将会重复定义;但是在类的继承层次中可以出现名字相同,参数列表相同而功能不同的函数,这是合法的,因为他们不在一个类中,但是,如果直接调编译系统将会按照同名覆盖的原则决定所调用的函数。例如:

class B
{
public:
    void test()
    {
        cout << "B::test()" << endl;
    }
};
class D :public B
{
public:
    void test()
    {
        cout << "D::test()" << endl;
    }
};
int main()
{
    D d;     //创建派生类的对象
    d.test();
}

结果:D::test()

在派生类中调用test()函数,将按照同名隐藏,优先访问派生类中的函数,这时如果要想访问继承下来的基类中的元素,可以添加作用域标识符:如d::B.test()。但是这样做很不方便,当程序比较大,很容易搞混。

鉴于以上的缺陷,人们用将基类中同名函数声明为虚函数,添加关键字virtual,通过同一个形式来达到不同的目的,既能调用派生类又能调用基类的同名函数,但是这种调用形式是用基类类型的指针或引用来调用的,例如将上代码稍加修改:

class B
{
public:
    virtual void test()   //声明为虚函数
    {
        cout << "B::test()" << endl;
    }
};
class D :public B
{
public:
virtual void test()
    {
        cout << "D::test()" << endl;
    }
};
int main()
{
    B*pB1 = new B;
    pB1->test();
    B*pB2 = new D;
    pB2->test();
    return 0;
}

此时输出:

B::test()

D::test()

说明:基类指针是指向基类对象的,如果用它指向派生类对象,则进行指针类型转换,将派生类型对象的指针先转换为基类的指针,所以基类指针指向的是派生类中基类部分,在程序修改前,是无法用基类指针去调用派生类对象的成员函数。

基类声明为虚函数后,派生类中的虚函数取代了基类原来的虚函数,因此使基类指针指向派生类对象后,调用虚函数就调用了派生类中的虚函数。。。

因此,在使用时,把基类中的某个成员声明为虚函数后,允许其在派生类中重新定义,赋予它新的功能,并且可以通过指向基类的指针或指向不同类的对象,从而调用其中的同名函数。

虚函数的使用方法:

1)、在基类中用virtual声明成员函数为虚函数,这样就可在派生类中重新定义次函数,为它赋予新的功能。
2)、在派生类中重新定义定义次函数时,要求函数名、函数类型、函数参数列表和类型都必须与基类的虚函数相同,然后根据派生类的需要重新定义函数体。
3)、定义一个指向基类的指针变量,并使他指向同一类族中需要调用该函数的对象。
4)、通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。
注:c++规定,当一个成员函数被声明为虚函数后,其派生类的同名函数自动成为虚函数,因此,在派生类中重新声明该函数时,可以加virtual,也可以不加,但是习惯上添加,为了保持程序逻辑更加清晰。。

函数重载和虚函数区别:

1、函数重载可以用于非成员函数和类的成员函数,而虚函数只能用于类的成员函数
2、函数重载是处理同一层次上横向的同名函数。
3、虚函数是处理不同层次纵向上的同名函数。
4、重载的函数必须具有相同的函数名,函数类型可以相同也可以不同,但函数的参数个数和参数类型二者中至少有一个不同,否则在编译时无法区分。而虚函数则要求同一类族中的所有虚函数的函数名,函数类型,函数的参数个数和参数类型都全部相同,否则就不是重定义了,也就不是虚函数了
5、函数重载是在程序编译阶段确定操作的对象的,属于静态关联。虚函数是在程序运行阶段确定操作对象的,属于动态关联。

纯虚函数

在成员函数的形参列表后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。
class B
{
    virtual void test() = 0;
};
int main()
{
    B b;  //错误,不能创建对象b;
    return 0;
}

1)构造函数不能声明为虚函数

构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功。编译器无法知道对象 的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类。无法确定。。。

2)静态函数不能给成虚函数

静态函数不是类的成员函数,而虚函数只是针对类的成员函数。

3)不建议将赋值运算符给成虚函数

对于赋值操作符,虽然可以在基类中将成员函数operator=定义成虚函数,但这样做并不会影响派生类中赋值操作符的使用。因为每个类有自己的赋值操作符。每个类的赋值操作符都有一个和类本身类型相同的形参,该类型必须不同于继承层次中任意其他类的赋值操作符的形参类型。因此子类的赋值操作符和基类的赋值操作符并不是同一个。但是,在这个子类中仍然有基类的那个操作符,但不是赋值操作符。将赋值操作符设为虚函数容易让人混淆,因为虚函数必须在基类和派生类中具有相同的形参,基类赋值操作符有一个形参是自身类类型的引用,如果该操作符为虚函数,则每个类都将得到一个虚函数成员,该成员定义了参数为一个基类对象的operator=。但是,对于派生类而言,这个操作符与赋值操作符是不同的。因此,将赋值操作符设为虚函数很容易令人混淆,并且没有什么用处。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值