多态与继承

1.多态

多态是通过虚函数来实现的,也就是说虚函数是允许子类重新定义成员函数,而子类通过定义和父类一样的函数的方法,被成为覆盖或者是重写。

多态的作用,使得代码可以重用,代码模块化;

函数重写:

(1)子类定义的函数与父类原型相同的函数

(2)函数的重写只有发生在父类和子类之间

  1. class Parent
  2. {
  3. public:
  4. void f()
  5. {
  6. cout << "Parent" << endl;
  7. }
  8. };
  9. class Child : public Parent
  10. {
  11. public:
  12. void f()
  13. {
  14. cout << "Child" << endl;
  15. }
  16. };
  17. int main()
  18. {
  19. Child c1;
  20. c1.f();
  21. while (1);
  22. }

打印出子类的同名函数:Child,除非使用 c1.Parent::f(); 才会执行 父类的打印函数,一般的情况是,编译器会将父类的打印函数进行隐藏,使用的是子函数重写的函数去执行,

  1. void run()
  2. {
  3. Child c1;
  4. c1.f();
  5. Parent *pp = &c1;
  6. pp->f(); // 父类的打印
  7. Parent &ppp = c1;
  8. ppp.f(); // 父类的打印
  9. }
  10. int main()
  11. {
  12. run();
  13. while (1);
  14. }

打印出来:

  1. Child
  2. Parent
  3. Parent

打印结果,居然和分析不一样,原因是:C和C++是静态编译型语言(编译器会根据指针的类型去判断执行的是一个什么用的对象),所以,我们的指针和引用的是 是 Parent,所以执行的时候,输出的结果是父类的打印函数。言而总之,总而言之,我们就看指针,指针是什么类型。

多态的本质:

通过添加 virtual 关键字对多态进行支持,将会被子类进行重写的函数,前面加上 virtual 关键字,

  1. class Parent
  2. {
  3. public:
  4. virtual void f()
  5. {
  6. cout << "Parent" << endl;
  7. }
  8. };
  9. class Child : public Parent
  10. {
  11. public:
  12. void f()
  13. {
  14. cout << "Child" << endl;
  15. }
  16. };
  17. void run()
  18. {
  19. Child c1;
  20. c1.f();
  21. Parent *pp = &c1;
  22. pp->f();
  23. Parent &ppp = c1;
  24. ppp.f();
  25. }
  26. 这三个打印输出的就是: child child child

只要在会被进行函数重写的函数假如 virtual 关键字,那么这个函数就是虚函数,到具体使用的时候,就会根据实际的情况进行打印输出。传入的是什么类型的,打印的就是什么类型的。

重载和重写的区别:什么时候重载、什么时候重写

(1)重载:

A 是同时存在多个同名的函数,但是在参数的个数,参数的类型、参数的顺序存在区别,

B 事实上,重载只能发生在一个类里面,继承是不能实现函数的重载。

C 原理上,C++编译器根据参数的不同,重新生成函数名,所以不同的参数会生成不同的函数名,所以本质上就是不同的函数了,也就是说编译器在编译的时候,就已经可以区分到底调用的是哪一个重载的函数,编译器早早已经确定,这些函数的编译的时候的地址就已经是被绑定了(早绑定)。

(2)重写:

A 是指子类重新定义父类的虚函数。子类重新定义了父类的虚函数,

B 必须是发生在父类和子类之间。 父类和子类中的函数,必须完全相同的原型

C 使用 virtual 可以产生多态

D 多态是在运行的期间跟根据具体的对象的类型决定调用函数。

将所有的函数都加上 virtual 关键字:

完全没有必要,这就涉及到虚函数的实现编译器将包含了 virtual 的虚函数的函数信息,存放到虚函数表里面,每次运行的时候,都会去虚函数表里面进行比对,看看是不是虚函数,如果是的话,那么就使用虚函数表里面的函数,不是的话,就去运行类内部其他的函数,所以不要将所有的函数全部设置为虚函数,会造成大量的浪费,处于效率考虑的话,其实就不要全部设置为虚函数。

纯虚函数:

是一种特殊的虚函数,在基类中(父类)不能对虚函数给据有意义的实现,而把他声明为纯虚函数,它的实现则留给子类去做,这就是纯虚函数的作用,

纯虚函数在父类只做函数原型的声明,而故意不定义函数体的虚函数,函数的定义等子类去完成(必须),这样就完成了纯虚函数的作用。

  1. class Shape
  2. {
  3. public: // 纯虚函数声明,没有实际的意义
  4. virtual double area() = 0;
  5. };
  6. class Rectangle : public Shape
  7. {
  8. double a;
  9. double b;
  10. public:
  11. Rectangle(double a, double b)
  12. {
  13. this->a = a;
  14. this->b = b;
  15. }
  16. // 函数的重写,纯虚函数重写
  17. double area()
  18. {
  19. return a * b;
  20. }
  21. };
  22. void area(Shape *s)
  23. {
  24. cout << s->area() << endl;
  25. }
  26. void run()
  27. {
  28. Rectangle rectangle(3, 4);
  29. cout<<"area is "<<rectangle.area()<<endl;
  30. area(&rectangle); // 可以使用指针
  31. //Shape shape; // 不能定义抽象类
  32. }

看到纯虚函数的声明是,virtual 函数 = 0; 告诉编译器,这个只是声明,所以必须在子类去实现这个函数;注意到: 抽象类(shape,包含了一个纯虚函数的类)已经是不能定义对象了,但是仍然可以使用指针。

注意:

不要将多态应用于数组当中,

多重继承:

多重继承就是 子类既继承自父类1,同时也继承父类2。实际的应用中,是不使用多重继承,




来自为知笔记(Wiz)

时间: 2024-11-03 21:42:42

多态与继承的相关文章

多态公有继承

多态公有继承:所谓多态公有继承,就是同一个方法在派生类和基类中的行为不同. 实现多态公有继承的机制:1,在派生类重新定义基类的方法.(用于对象)2,使用虚方法(多用于指针和引用),虚方法在基类用关键字virtual声明,在派生类中会自动识别基类中声明的虚方法.所以,在派生类中可以用(也可以不用)virtual显式标出哪个方法是虚方法.通俗来讲:为了实现一种方法可以在派生类和基类中的行为不同,于是在派生类中重新定义基类函数的方法(比如基类有方法A, 但又在派生类中重新定义了方法A, 它们名字一样,

七:Java之封装、抽象、多态和继承

本文章介绍了关于Java中的面向对象封装.抽象.继承.多态特点 Java面向对象主要有四大特性:封装.抽象.继承和多态. 一.封装 封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成"类",其中数据和函数都是类的成员. 在面向对象语言中,封装特性是由类来体现的,我们将现实生活中的一类实体定义成类,其中包括属性和行为(在Java中就是方法),就好像人类,可以具有name,sex,age等属性,同时也具有eat(),sle

深入浅出OOP(四): 多态和继承(抽象类)

在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时多态) 深入理解OOP(四):多态和继承(C#中的抽象类) 深入理解OOP(五):C#中的访问修饰符(Public/Private/Protected/Internal/Sealed/Cons

深入理解OOP(二):多态和继承(继承)

本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时多态) 深入理解OOP(四):多态和继承(C#中的抽象类) 深入理解OOP(五):C#中的访问修饰符(Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields) 深入理解OOP(六):枚举(实用方法)

Swift3.0 多态 、继承 、 强制转换

又有点空开始瞎BB一下,写写博客了.这几天发现了一个现象,在博客园特别能吸粉的,只有两类人,一种大神 .一种 美女程序媛,看到大神呢,默默的粉一个,毕竟还是得好好学学人家的,看到美女程序媛呢,默默地多看两眼,从来也不粉,就这样静静的装着B,没办法,习惯了..估计也有很多像我这样,有时间就写写的孩纸其实挺多的,有时候吧,粉不粉这种事,不能太认真.一你不是大神,二不是漂亮MM.写点东西,就是想告诉自己,有时间其实你也在前进着,快慢不说,至少没停下吧.该有的都会有的.不瞎BB了,说主题,3.0 的多态

重写,重载,多态,继承的区别。

重写,重载,多态,继承的区别: 继承是子类继承父类的方法: 重写(override)是子类重写父类允许访问的方法.返回值和参数类型必须相同. 重载(overload)就是允许多个同名但是形参个数或者类型不同的函数方法存在于同一个类里.当类统一调用方式时由形参来决定调用具体的方法. 下面是转载的一篇文章: 继承是子类获得父类的成员,重写是继承后重新实现父类的方法.重载是在一个类里一系列参数不同名字相同的方法.多态则是为了避免在父类里大量重载引起代码臃肿且难于维护. 网上看到一个有趣的说法是:继承是

.NET Core CSharp初级篇 1-6 类的多态与继承

.NET Core CSharp初级篇 1-6 本节内容为类的多态与继承 简介 终于讲到了面向对象三大特性中的两大特性--继承与多态.通过继承与多态,我们能很好的将类的拓展性发挥到了极致.在下面的内容讲解中,我们将从各个方面对继承和多态进行刨析. 继承 继承事实上是一个非常好理解的语法,在C#中实现继承使用A:B,表示A类继承B类.子类(一称为派生类)继承于父类(一称为基类)就好比孩子继承了父亲的一切,但是孩子总归是有自己的个性的,而父亲也有一些不会告诉孩子的事情.如果我们从之前的访问控制符这一

C++多态公有继承

面向对象的三个基本特征 面向对象的三个基本特征是:封装.继承.多态.其中,封装可以隐藏实现细节,使得代码模块化:继承可以扩展已存在的代码模块(类):它们的目的都是为了——代码重用.而多态则是为了实现另一个目的——接口重用! 多态: 为了使同一方法在基类和派生类中的实现可以不同. 多态的实现: 1.在派生类中重新定义基类的方法 2.使用虚方法 如果要在派生类中重新定义基类的方法,通常将基类方法声明为虚方法 如果方法是通过引用或指针调用而不是对象直接调用,使用哪一种方法将有两种情况: 1.如果在基类

多态&amp;抽象&amp;继承

多态 package cn.itcast.extend; public class ExtendDemo2 { public static void main(String[] args) { A a=new B();//多条 System.out.println(a.num); a.show();//非静态 a.say();//静态方法 } } class A{ int num=10; //静态方法 public static void say(){ System.out.println("父

深究继承示例(多态,继承,构造函数)

关于继承,为什么一直说在含有构造函数的继承中,父类中一定要有不含参数的构造函数才可以. 首先说明默认值的一个知识点:在定义全局变量的时候,即使不给变量赋值,变量也是有值的,比如整形变量的默认值是0 package day07; public class Trys { private static int p ; public static void main(String[] args) { System.out.println(p); } }0 *但是局部变量就必须赋值,不赋值是没法输出的.