C++ 多态 拼搏现实的明天。 2023-07-24 08:03 50阅读 0赞 ### C++ 多态 ### * 一、多态性 * * 1、多态性的定义 * 2、多态性的分类及实现方式 * 3、动态多态的作用 * 4、虚函数的注意事项 * 5、构成多态的条件 * 6、什么时候声明虚函数 * 二、动态绑定和静态绑定 * * 1、函数名联编 * 2、静态绑定 * 3、动态绑定 * 4、静态联编与动态联编的比较 * 5、需要动态联编的情况 * 三、多态实现的机制 * * 虚函数的工作原理 * 四、多态的优缺点 * * 1、优点 * 2、缺点 # 一、多态性 # ## 1、多态性的定义 ## > “多态(polymorphism)”指的是同一名字的事物可以完成不同的功能 ## 2、多态性的分类及实现方式 ## > 多态分为两种: > 1)、编译时的多态性(静态多态):通过函数重载和函数模板实现 > 2)、运行时的多态性(动态多态):通过虚函数实现 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjcwNDA5MA_size_16_color_FFFFFF_t_70_pic_center] ## 3、动态多态的作用 ## > 没有实现多态的时候,基类指针只能访问派生类的成员变量,但是不能访问派生类的成员函数,当实现多态之后,基类指针就既可以访问派生类的成员变量也可以访问派生类的成员函数 示例: #include <iostream> using namespace std; //基类 class Base { protected: int m_a; public: Base(int a) { m_a = a; } void display() { cout << "m_a = " << m_a << " 这是基类的display() " << endl; } }; //派生类 class Derive: public Base { protected: int m_b; public: Derive(int a, int b) : Base(a) { m_b = b; } void display() { cout << "m_b = " << m_b << " 这是派生类的display()" << endl; } }; int main() { Base *p = new Base(1); p->display(); p = new Derive(3, 2); p->display(); return 0; } 运行结果: m_a = 1 这是基类的display() m_a = 3 这是基类的display() > 上述示例中,如果指针指向了派生类对象,那么就应该使用派生类的成员变量和成员函数,但是运行结果却告诉证明事实并不是如此,当基类指针 p 指向派生类Derive的对象时,虽然使用了 Derive的成员变量,但是却没有使用它的成员函数,导致输出结果不符合预期。 > 为此,如果要实现基类指针指向基类对象时调用基类方法、基类指针指向派生类对象时调用派生类方法的功能,这就需要多态性来实现,而多态性是由虚函数来实现的。 在上面示例中,只需将基类中的display()声明为虚函数便可实现多态 #include <iostream> using namespace std; //基类 class Base { protected: int m_a; public: Base(int a) { m_a = a; } virtual void display() { cout << "m_a = " << m_a << " 这是基类的display() " << endl; } }; //派生类 class Derive: public Base { protected: int m_b; public: Derive(int a, int b) : Base(a) { m_b = b; } void display() { cout << "m_b = " << m_b << " 这是派生类的display()" << endl; } }; int main() { Base *p = new Base(1); p->display(); p = new Derive(3, 2); p->display(); return 0; } 运行结果: m_a = 1 这是基类的display() m_b = 2 这是派生类的display() 借助引用也可以实现多态,不过指针可以随时改变指向,而引用只能指代固定的对象 #include <iostream> using namespace std; //基类 class Base { protected: int m_a; public: Base(int a) { m_a = a; } virtual void display() { cout << "m_a = " << m_a << " 这是基类的display() " << endl; } }; //派生类 class Derive: public Base { protected: int m_b; public: Derive(int a, int b) : Base(a) { m_b = b; } void display() { cout << "m_b = " << m_b << " 这是派生类的display()" << endl; } }; int main() { Base b(1); Derive d(3, 2); Base &rb = b; Base &rd = d; rb.display(); rd.display(); return 0; } 运行结果: m_a = 1 这是基类的display() m_b = 2 这是派生类的display() ## 4、虚函数的注意事项 ## > 1)、 只需要在虚函数的声明处加上 virtual 关键字,函数定义处可以加也可以不加; > 2)、 将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽关系的同名函数都将自动成为虚函数; > 3) 、当在基类中定义了虚函数时,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数; > 4)、 只有派生类的虚函数覆盖基类的虚函数(函数原型相同)才能构成多态(通过基类指针访问派生类函数); > 5)、 构造函数不能是虚函数。对于基类的构造函数,它仅仅是在派生类构造函数中被调用,这种机制不同于继承。也就是说,派生类不继承基类的构造函数,将构造函数声明为虚函数没有什么意义; > 6) 、析构函数可以声明为虚函数,而且有时候必须要声明为虚函数 ## 5、构成多态的条件 ## > 1)、必须存在继承关系; > 2)、继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同); > 3)、存在基类的指针,通过该指针调用虚函数 ## 6、什么时候声明虚函数 ## > 首先看成员函数所在的类是否会作为基类; > 然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数 # 二、动态绑定和静态绑定 # ## 1、函数名联编 ## > 程序调用函数时,编译器将源代码中的函数调用解释为执行特定的函数代码块称之为函数名联编 ## 2、静态绑定 ## > 静态绑定也叫静态联编或早期联编,是指在编译阶段进行的函数名联编。也就是说如果有多个重载函数,在编译阶段就确定了要执行哪个函数 ## 3、动态绑定 ## > 动态绑定也叫动态联编或晚期联编,是指编译器在运行阶段进行的函数名联编。当有虚函数存在时,无法在编译阶段确定执行哪个函数,因为编译器无法确定用户会选择哪种类型的对象,所以只能在程序运行来确定执行哪个函数 ## 4、静态联编与动态联编的比较 ## > 1)、默认联编方式:静态联编是默认的联编方式 > 2)、效率比较:静态联编的效率高于动态联编,因为动态联编需要追踪基类指针或引用指向的对象类型 ## 5、需要动态联编的情况 ## > 1)、类不会用作基类 > 2)、派生类不重新定义基类的任何方法 # 三、多态实现的机制 # > 多态是借助虚函数实现的,多态的实现机制其实就是虚函数的工作机制 ## 虚函数的工作原理 ## > 编译器会为每个对象添加一个隐藏成员,这个成员保存了一个指向函数地址数组的指针,这个函数地址数组称之为虚函数表(virtual function table, vtbl)。虚函数表中存储了为类对象声明的虚函数的地址。 > 例如,基类对象包含一个指向基类中所有虚函数地址表的指针,派生类对象包含一个指向派生类中所有虚函数地址表的指针。如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址,若派生类没有提供虚函数的定义,则保存函数原始版本的地址 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjcwNDA5MA_size_16_color_FFFFFF_t_70_pic_center 1] # 四、多态的优缺点 # ## 1、优点 ## > 1)、提高了代码的可扩展性 > 2)、多态可以增加灵活性,使用基类指针使用基类方法和派生类方法 ## 2、缺点 ## > 1)、不能使用子类的特有属性和行为 > 2)、在内存和执行速度方面有一定的成本 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjcwNDA5MA_size_16_color_FFFFFF_t_70_pic_center]: /images/20230528/aa6d6c7243494806b1899e18fd84391b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjcwNDA5MA_size_16_color_FFFFFF_t_70_pic_center 1]: /images/20230528/614a26cb4fcf49e4a07d833c29ed0dee.png
相关 c++多态 class Parent \{ public: virtual void fun() \{ cout << "Parent" << endl; \} 怼烎@/ 2024年02月17日 20:52/ 0 赞/ 97 阅读
相关 C++ 多态 C++ 多态 一、多态性 1、多态性的定义 2、多态性的分类及实现方式 3、动态多态的作用 4、虚函数的注意事 拼搏现实的明天。/ 2023年07月24日 08:03/ 0 赞/ 51 阅读
相关 C++多态 [浅谈C++多态性][C] [虚函数和纯虚函数的区别][Link 1] [虚函数][Link 2] [C++虚函 我就是我/ 2022年09月24日 12:25/ 0 赞/ 256 阅读
相关 【C#】 多态 多态是面向对象编程中三大机制之一,其原理建立在"从父类继承而来的子类可以转换为其父类"这个规则之上,换句话说,能用父类的地方,就能用该类的子类.当从父类派生了很多子 深碍√TFBOYSˉ_/ 2022年08月18日 15:24/ 0 赞/ 217 阅读
相关 C++多态 多态意思是”多种形态“。多态性是面向对象编程的关键思想。 C++通过以下方式支持多态 (1)经由一组隐式的转化操作。例如把一个派生类的指针转化为一个指向公共基类的指针 £神魔★判官ぃ/ 2022年08月06日 01:17/ 0 赞/ 265 阅读
相关 【c++】多态 多态 多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。 C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执 男娘i/ 2022年07月11日 13:13/ 0 赞/ 243 阅读
相关 C#(多态) 1: 在C\语言中,重载和重写的区别 (1)重写: 重写是子类的方法覆盖父类的方法,要求方法名和参数都相同 (2)重载:重载是在同一个类中的 偏执的太偏执、/ 2021年12月11日 03:11/ 0 赞/ 294 阅读
相关 C++多态 C++多态 多态概念 字面意思,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 举个例子:假如你要去看电影,有的影院也许有这样的规定 我不是女神ヾ/ 2021年11月27日 06:52/ 0 赞/ 373 阅读
还没有评论,来说两句吧...