美文网首页
C++学习(6)多态

C++学习(6)多态

作者: su945 | 来源:发表于2020-08-13 22:34 被阅读0次

1.虚函数和多态

  • 在类的定义中,前面有virtual关键字的成员函数就是虚函数。
  • virtual关键字只用在类定义里的函数说明中,写函数体时不用。

  • 多态的表现形式一
    派生类的指针可以赋给基类指针。
    通过基类指针调用基类和派生类中的同名虚函数时:
    (1)若该指针指向一个基类的对象,那么被调用是
    基类的虚函数;
    (2)若该指针指向一个派生类的对象,那么被调用
    的是派生类的虚函数。
    这种机制就叫做“多态”。
class CBase {
public:
    virtual void SomeVirtualFunction() { }
};
class CDerived :public CBase {
public:
    virtual void SomeVirtualFunction() { }
};
int main() {
    CDerived ODerived;
    CBase * p = &ODerived;
    p->SomeVirtualFunction(); //调用哪个虚函数取决于p指向哪种类型的对象
    return 0;
}

  • 多态的表现形式二
    派生类的对象可以赋给基类引用
    通过基类引用调用基类和派生类中的同名虚函数时:
    (1)若该引用引用的是一个基类的对象,那么被调
    用是基类的虚函数;
    (2)若该引用引用的是一个派生类的对象,那么被
    调用的是派生类的虚函数。
    这种机制也叫做“多态”。
class CBase {
public:
    virtual void SomeVirtualFunction() { }
};
class CDerived :public CBase {
public:
    virtual void SomeVirtualFunction() { }
};
int main() {
    CDerived ODerived;
    CBase & r = ODerived;
    r.SomeVirtualFunction(); //调用哪个虚函数取决于r引用哪种类型的对象
    return 0;
}

  • 多态的作用
    在面向对象的程序设计中使用多态,能够增强程序的可扩充性,即程序需要修改或增加功能的时候,需要改动和增加的代码较少。

用基类指针数组存放指向各种派生类对象的指针,然后遍历该数组,就能对各个派生类对象做各种操作,是很常用的做法

  • 构造函数和析构函数中调用虚函数
    在构造函数和析构函数中调用虚函数,不是多态。编译时即可确定,调用的函数是自己的类或基类中定义的函数,不会等到运行时才决定调用自己的还是派生类的函数。

2.多态的实现原理

“多态” 的关键在于通过基类指针或引用调用
一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定 ---- 这叫“动态联编” 。

  • 多态实现的关键 --- 虚函数表
    每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中都放着虚函数表的指针。虚函数表中列出了该类的虚函数地址。 多出来的4个字节就是用来放虚函数表的地址的。


    批注 2020-08-13 221906.png

3.虚析构函数

  • 通过基类的指针删除派生类对象时,通常情况下只调用基类的析构函数
     但是,删除一个派生类的对象时,应该先调用派生类的析构函数,然后调用基类的析构函数。
    解决办法:把基类的析构函数声明为virtual
     派生类的析构函数可以virtual不进行声明
     通过基类的指针删除派生类对象时,首先调用派生类的析构函数,然后调用基类的析构函数
     一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数。或者,一个类打算作为基类使用,也应该将析构函数定义成虚函数。
    注意: 不允许以虚函数作为构造函数
class son {
public:
    ~son() { cout << "bye from son" << endl; };
};
class grandson :public son {
public:
    ~grandson() { cout << "bye from grandson" << endl; };
};
int main() {
    son *pson;
    pson = new grandson();
    delete pson;
    return 0;
}
//输出: bye from son 没有执行grandson::~grandson()!!!
class son {
public:
    virtual ~son() { cout << "bye from son" << endl; };
};
class grandson :public son {
public:
    ~grandson() { cout << "bye from grandson" << endl; };
};
int main() {
    son *pson;
    pson = new grandson();
    delete pson;
    return 0;
}
//输出: bye from grandson
//bye from son
//执行grandson::~grandson(),引起执行son::~son()!!!

4.纯虚函数和抽象类

 纯虚函数: 没有函数体的虚函数

class A {
private: int a;
public:
    virtual void Print() = 0; //纯虚函数
    void fun() { cout << "fun"; }
};
  • 包含纯虚函数的类叫抽象类
     抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
     抽象类的指针和引用可以指向由抽象类派生出来的类的对象
A a ; // 错, A 是抽象类,不能创建对象
A * pa ; // ok,可以定义抽象类的指针和引用
pa = new A ; //错误, A 是抽象类,不能创建对象
  • 在抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部
    不能调用纯虚函数。
  • 如果一个类从抽象类派生而来,那么当且仅当它实现了基类中的所有纯虚函
    数,它才能成为非抽象类。
class A {
public:
    virtual void f() = 0; //纯虚函数
    void g() {
        this->f(); //ok
    }
    A() { //f( ); // 错误
    }
};
class B :public A {
public:
    void f() { cout << "B:f()" << endl; }
};
int main() {
    B b;
    b.g();
    return 0;
}

相关文章

  • C++学习(6)多态

    1.虚函数和多态 在类的定义中,前面有virtual关键字的成员函数就是虚函数。 virtual关键字只用在类定义...

  • 深刻剖析之c++博客文章

    三大特性 封装、继承、多态 多态 C++ 虚函数表解析C++多态的实现原理 介绍了类的多态(虚函数和动态/迟绑定)...

  • 多态的C++实现

    多态的C++实现 1 多态的原理 什么是多态?多态是面向对象的特性之一,只用父类指针指向子类的对象。 1.1 多态...

  • C++ 的多态(Polymorphism), virtual f

    多态 c++支持两种多态,编译时多态和运行时多态但其实编译时多态根本不是真正的多态,编译时多态就是函数的重载,ov...

  • c++多态 学习笔记

    今天印象最深的就是学习c++多态这一块了,年幼的时候听说过这个东西,但限于当时的眼界太窄,对于这块东西没有深入研究...

  • C++学习笔记(3)

    摘要:本篇对C++的三个重点「封装,继承,多态」的学习总结与使用。 很遗憾,在坚持了一段时间c++的学习后,有点想...

  • C++第六篇多态

    C++中的多态性分为编译时多态性和运行时多态性,编译时多态通过函数重载和模板体现,运行多态通过虚函数体现编译、连接...

  • 5-C++远征之离港篇-学习笔记

    C++远征离港篇 离港总动员 C++远征计划的学习者肯定是冲着封装,继承,多态来的。 知识点: 指针 VS 引用 ...

  • 面试题目收集总结

    C++: 多态: 多态性都有哪些?(静态和动态,然后分别叙述了一下虚函数和函数重载) c语言和c++有什么区别?(...

  • C++的多态

    C++三大特性:封装、继承和多态。其中最好理解的就是封装了,继承作为C++面向对象的特征也不难理解,那么多态,应该...

网友评论

      本文标题:C++学习(6)多态

      本文链接:https://www.haomeiwen.com/subject/dzjvdktx.html