C+继承之同名覆盖,函数重写与多态详解

目录
  • 同名覆盖
  • 函数重写
  • 多态
  • 总结

如果父类成员和子类成员名字相同是否允许?会发生什么?

同名覆盖

#include<iostream>
using namespace std;
class Base
{
public:
    int m_data;
    Base():m_data(1)//父类初始化为1
    {  }
};
class Derived : public Base
{
public:
    int m_data;
    Derived():m_data(2)//子类初始化为2
    {  }
};
int main()
{
    Derived d;
    //父类的m_data被隐藏了,但仍存在,可以通过::符访问
    cout<<"base data: "<<d.Base::m_data<<endl;
    //直接访问m_data得到的是子类成员的值
    cout<<"derived data: "<<d.m_data<<endl;
    //验证两个int刚好是8字节,说明d对象有两个整型数
    cout<<sizeof(d)<<endl;
    return 0;
}

运行结果

base data: 1
derived data: 2
8

说明父类和子类是允许存在同名成员的,只不过父类的成员被编译器隐藏了,正常访问得到的是子类成员的值。

那么如果是函数同名呢?

函数重写

函数重写是同名覆盖的一种特殊情况,即子类中重新实现父类中的同名函数,属于同名覆盖

#include<iostream>
using namespace std;
class Base
{
public:
    void print()
    {
        cout<<"Base class"<<endl;
    }
};
class Derived : public Base
{
public:
    void print()
    {
        cout<<"Derived class"<<endl;
    }
};
int main()
{
    Derived d;
    d.Base::print();//父类函数被隐藏
    d.print();
    return 0;
}

运行结果

Base class
Derived class

如果调用how_to_print函数,期望传入父类对象时调用父类打印函数,传入子类对象时调用子类对象函数

void how_to_print(Base* p)
{
    p->print();//期望根据对象选择相应函数,不能实现
}
int main()
{
    Base b;
    Derived d;
    how_to_print(&b);
    how_to_print(&d);
    return 0;
}

结果却是都打印Base class

Base class
Base class

结果没有符合预期,分析:

1.传入父类对象b的地址时,父类指针指向父类对象,打印正常;

2.传入子类对象d的地址时,父类指针指向子类对象,此时由于赋值兼容性(子类对象可以当作父类对象使用),子类对象退化为父类对象(父类指针只能访问父类成员),编译器认为父类指针指向的是父类对象,因此最终调用了父类的打印函数

以上结果是合理的,却没有符合预期的目的,这也是函数重写带来的问题。如果不能实现以上目的,函数重写是没有意义的,那么如何实现父类指针(引用)指向:

  • 父类对象,调用父类函数
  • 子类对象,调用重写函数

实际上以上行为就是多态

多态

所谓多态,即同样的调用语句,在实际运行时存在不同的表现状态,依据则是对象的类型不同

要实现上文中函数重写的多态,需要引入virtual关键字,C++原生支持多态

  • 通过使用virtual关键字对多态进行支持
  • 被virtual声明的函数被重写后具有多态特性
  • 被virtual声明的函数叫做虚函数

在父类函数print声明前添加virtual关键字,print函数成为虚函数,子类重写的函数也将自动变成虚函数,这样就可以实现多态

class Base
{
public:
    virtual void print()//加virtual变成了虚函数
    {
        cout<<"Base class"<<endl;
    }
};

运行结果

Base class
Derived class

多态的意义:

在程序运行过程中展现出动态的特性函数重写必须多态实现,否则没有意义多态是面向对象组件化程序设计的基础特性

总结

同名覆盖是继承时发生在父类和子类之间,子类同名成员覆盖(屏蔽)父类同名成员的现象;函数重写也是同名覆盖,函数重写多态实现才有意义,C++通过virtual支持多态多态是面向对象组件化程序设计的基础特性

(0)

相关推荐

  • C++中的多态与多重继承实现与Java的区别

    多态问题 笔者校招面试时被问到了著名问题「C++ 与 Java 如何实现多态」,然后不幸翻车.过于著名反而没有去准备,只知道跟虚函数表有关.面试之后比较了 C++ 和 Java 多态的实现的异同,一并记录在这里. C++ 多态的虚指针实现 首先讨论 C++. 多态也即子类对父类成员函数进行了重写 (Override) 后,将一个子类指针赋值给父类,再对这个父类指针调用成员函数,会调用子类重写版本的成员函数.简单的例子: class Parent1 { public: virtual void s

  • C++中重载、重写(覆盖)和隐藏的区别实例分析

    本文实例讲述了C++中重载.重写(覆盖)和隐藏的区别,对于C++面向对象程序设计来说是非常重要的概念.具体分析如下: 1.重载:重载从overload翻译过来,是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型. 示例代码如下: class A{ public: void test(int i); void test(double i); void test(int i, double j); void te

  • C++中继承与多态的基础虚函数类详解

    前言 本文主要给大家介绍了关于C++中继承与多态的基础虚函数类的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 虚函数类 继承中我们经常提到虚拟继承,现在我们来探究这种的虚函数,虚函数类的成员函数前面加virtual关键字,则这个成员函数称为虚函数,不要小看这个虚函数,他可以解决继承中许多棘手的问题,而对于多态那他更重要了,没有它就没有多态,所以这个知识点非常重要,以及后面介绍的虚函数表都极其重要,一定要认真的理解~ 现在开始概念虚函数就又引出一个概念,那就是重写(覆

  • C++中的封装、继承、多态理解

    封装(encapsulation):就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成"类",其中数据和函数都是类的成员.封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,特定的访问权限来使用类的成员.封装可以隐藏实现细节,使得代码模块化. 继承(inheritance):C++通过类派生机制来支持继承.被继承的类型称为基类或超类,新产生的类为派生类或子类.保持已有类的特性而构造新类的过

  • C语言模式实现C++继承和多态的实例代码

    这个问题主要考察的是C和C++的区别,以及C++中继承和多态的概念. C和C++的区别 C语言是面向过程的语言,而C++是面向对象的过程. 什么是面向对象和面向过程? 面向过程就是分析解决问题的步骤,然后用函数把这些步骤一步一步的进行实现,在使用的时候进行一一调用就行了,注重的是对于过程的分析.面向对象则是把构成问题的事进行分成各个对象,建立对象的目的也不仅仅是完成这一个个步骤,而是描述各个问题在解决的过程中所发生的行为. 面向对象和面向过程的区别? 面向过程的设计方法采用函数来描述数据的操作,

  • C++多继承多态的实例详解

    C++多继承多态的实现 如果一个类中存在虚函数,在声明类的对象时,编译器就会给该对象生成一个虚函数指针,该虚函数指针指向该类对应的虚函数表. 多态的实现是因为使用了一种动态绑定的机制,在编译期间不确定调用函数的地址,在调用虚函数的时候,去查询虚函数指针所指向的虚函数表. 派生类生成的对象中的虚函数指针指向的是派生类的虚函数表,因此无论是基类还是派生来调用,都是查询的是派生类的表,调用的是派生类的函数. 如果发生了多继承,多个基类中都有虚函数,那么该是怎样的呢?虚函数指针如何排列,多个基类的指针为

  • C++多重继承及多态性原理实例详解

    一.多重继承的二义性问题 举例: #include <iostream> using namespace std; class BaseA { public: void fun() { cout << "A.fun" << endl; } }; class BaseB { public: void fun() { cout << "B.fun" << endl; } void tun() { cout &l

  • C+继承之同名覆盖,函数重写与多态详解

    目录 同名覆盖 函数重写 多态 总结 如果父类成员和子类成员名字相同是否允许?会发生什么? 同名覆盖 #include<iostream> using namespace std; class Base { public: int m_data; Base():m_data(1)//父类初始化为1 { } }; class Derived : public Base { public: int m_data; Derived():m_data(2)//子类初始化为2 { } }; int ma

  • C++/java 继承类的多态详解及实例代码

    C++/java 继承类的多态详解 学过C++和Java的人都知道,他们二者由于都可以进行面向对象编程,而面向对象编程的三大特性就是封装.继承.多态,所有今天我们就来简单了解一下C++和Java在多态这方面的不同. 首先我们各看一个案例. C++ //测试继承与多态 class Animal { public: char name[128]; char behavior[128]; void outPut() { cout << "Animal" << endl

  • Python面向对象编程之继承与多态详解

    本文实例讲述了Python面向对象编程之继承与多态.分享给大家供大家参考,具体如下: Python 类的继承 在OOP(Object Oriented Programming)程序设计中,当我们定义一个class的时候,可以从某个现有的class 继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Base class.Super class). 我们先来定义一个class Person,表示人,定义属性变量 name 及 sex (姓名和性别): 定义一

  • Vue3使用hooks函数实现代码复用详解

    目录 前言 VUE2我们是怎么做的呢? VUE3中我们怎么处理复用代码逻辑的封装呢? 说那么多,不如直接上代码来看差异 前言 项目开发过程中,我们会遇到一些情况,就是多个组件都可以重复使用的一部分代码逻辑,功能函数,我们想要复用,这可怎么办呢? VUE2我们是怎么做的呢? 在vue2 中有一个东西:Mixins 可以实现这个功能 mixins就是将这些多个相同的逻辑抽离出来,各个组件只需要引入mixins,就能实现代码复用 弊端一: 会涉及到覆盖的问题 组件的data.methods.filte

  • Java OOP三大特征之封装继承与多态详解

    目录 封装 继承 多态 OOP语言的三大特征即:面向对象的三个比较重要的思想 封装 官话:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口进行交互 通俗讲,不让类外看到实现的细节,通过技术手段对这些细节包装一个外壳,同时提供几个公开的接口,让你进行交互即可(例如:手机,内部的具体零件,不会让你观察到,使用者只能看到外壳,通过外壳的显示屏,充电口进行交互)简而言之——套壳屏蔽细节 实际上通过private来实现 例如: 继承 面向对象的思想中提出了继承的概念,专门用来进

  • PHP中的函数声明与使用详解

      函数 1.  函数名是标识符之一,只能有字母数字下划线,开头不能是数字: 函数名的命名,必须符合"小驼峰法则"FUNC(),func(),Func(); 函数名不区分大小写; 函数名不能与已有函数同名,不能与内置函数名同名: 2.   function_exists("func");用于检测函数是否已经声明: 注意传入的函数名,必须是字符串格式,返回结果为true/false: echo打印时,true为1,false不显示:               [ph

  • ES6中Array.copyWithin()函数的用法实例详解

    ES6为Array增加了copyWithin函数,用于操作当前数组自身,用来把某些个位置的元素复制并覆盖到其他位置上去. Array.prototype.copyWithin(target, start = 0, end = this.length) 该函数有三个参数. target:目的起始位置. start:复制源的起始位置,可以省略,可以是负数. end:复制源的结束位置,可以省略,可以是负数,实际结束位置是end-1. 例: 把第3个元素(从0开始)到第5个元素,复制并覆盖到以第1个位置

  • C++ 中友元函数与友元类详解

    C++ 中友元函数与友元类详解 总的来说,友元分为两类:友元函数与友元类.友元是针对类而言,它提供了一种非类的成员函数来访问类的非公有成员的一种机制.可以把一个函数指定为某类的友元,这个函数称为这个类的友元函数.也可以将类A指定为类B的友元,则类A是类B的友元类,类A的所有成员函数均是类B的友元函数,均可以访问类B的非公有成员.        友元函数的注意事项: (1)友元函数不是类的成员函数,在函数体中访问对象的成员,必须用"对象名.对象成员"方式来访问, 友元函数可以访问类中的所

  • Python常用内置函数和关键字使用详解

    目录 常用内置方法 查看所有的内置类和内置方法 标准输入输出 数学 序列 进制数转换 ASCII字符编码转换 其它 常用关键字 常见内置属性 常用内置方法 在Python中有许许多多的内置方法,就是一些Python内置的函数,它们是我们日常中经常可以使用的到的一些基础的工具,可以方便我们的工作. 查看所有的内置类和内置方法 # 方法一 built_list = dir(__builtins__) # 方法二 import builtins built_list = dir(builtins) 其

  • 前端算法之TypeScript包含min函数的栈实例详解

    目录 前言 思路梳理 实现代码 示例代码 前言 基于数据结构: “栈”,实现一个min函数,调用此函数即可获取栈中的最小元素.在该栈中,调用min.push.pop的时间复杂度都是O(1). 本文就跟大家分享下这个算法,欢迎各位感兴趣的开发者阅读本文. 思路梳理 相信大多数开发者看到这个问题,第一反应可能是每次往栈中压入一个新元素时,将栈里的所有元素排序,让最小的元素位于栈顶,这样就能在O(1)的时间内得到最小元素了.但这种思路不能保证最后入栈的元素能够最先出栈,因此这个思路行不通. 紧接着,我

随机推荐