C++虚函数作用原理(二)——类的继承

上一篇博客

C++虚函数作用原理(一)

开始

上一篇博客我们了解了虚函数到底是怎么存在的,那么这一篇我们就要开始考虑:虚函数的继承问题了。
首先我们可以回忆一下,我们之前在学习继承的时候存在函数覆盖这个概念。如果没有函数覆盖,那么当我们调用子类中和父类同名函数时,就会出现二义性,编译器无法知道你到底需要哪一个函数。那么对于虚函数的继承我们是不是也应该考虑同名函数的覆盖问题呢?————当然应该,那么这里我们就来通过代码验证一下:

class A
{
    int x;
    int y;
public:
    virtual void out()
    {
        cout << x << y << endl;
        cout << "A" << endl;
    }
    virtual void out_1()
    {
        cout << x << y << endl;
    }

};
class B :public A
{
    void cout_1()
    {
        cout << "B"<<endl;
    }
    virtual void cout_4()//重写的一个虚函数
    {
        cout << "B1"<<endl;
    }
};
int main()
{
    A a;
    B b;
    return 0;
}

成员的分布:


这个图中我们可以知道:
继承类B完全继承了A的所有成员,并且我们发现B只有虚函数表指针和A的虚函数表指针不一样,但是被B重写的函数void out()的地址是与A的地址一样这就说明继承类把父类的虚函数覆盖了。这里就验证了虚函数覆盖这一说法!
备注:这里我们也可以观察到B类单独写的虚函数

virtual void cout_4()//重写的一个虚函数
    {
        cout << "B1"<<endl;
    }

并没有出现在虚函数表指针指向的表里面,它真的不在吗?当然不是,只是我们看不到而已。现在我们写一段代码来看看他到底在虚函数表里面吗?

int main()
{
    A a;
    B b;
    cout << "继承来的函数——void out()的地址:" << (int*)*(int *)&b << endl;
    cout << "继承来的函数——void out_1()的地址:" << (((int*)*(int *)&b)+1)<< endl;
    cout << "B类自己的函数——void out_4()的地址:" << (((int*)*(int *)&b) + 2) << endl;
    return 0;
}

运行结果:


这段代码运行的结果告诉我们其实,子类自己写的虚函数是在虚函数的表里面的只是没有显示出来。

原文地址:https://www.cnblogs.com/kadcyh/p/11844497.html

时间: 2024-10-29 04:39:46

C++虚函数作用原理(二)——类的继承的相关文章

OOP2(虚函数/抽象基类/访问控制与继承)

通常情况下,如果我们不适用某个函数,则无需为该函数提供定义.但我们必须为每个虚函数都提供定义而不管它是否被用到了,这因为连编译器也无法确定到底会适用哪个虚函数 对虚函数的调用可能在运行时才被解析: 当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定应该调用哪个版本的函数.被调用的函数是与之绑定到指针或引用上的对象的动态类型相匹配的那一个 注意:动态绑定只有当我们通过指针或引用调用虚函数时才会发生.当我们通过一个具有普通类型(非引用非指针)的表达式调用虚函数时,在编译时就会将调用

c++之虚函数和基类指针

1. 基类指针虽然获取派生类对象地址,却只能访问派生类从基类继承的成员 1 #include <iostream> 2 using namespace std; 3 4 //通过基类指针只能访问从基类继承的成员 5 class A 6 { 7 public: 8 A(char x) 9 { 10 this->x = x; 11 } 12 //void virtual who() //基类定义虚函数,则派生类的重定义版本默认为虚函数 13 void who() //除非定义虚函数,否则基类

基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针

您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. 百度和网页 http://bbs.csdn.net/topics/380238133 的作者无关,不对其内容负责.百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面. 首页 精选版块 移动开发 iOS Android Qt WP 云计算 IaaS Pass/SaaS 分布式计算/Hadoop J

派生表中第一个基类没有虚函数,派生类存在虚函数时的内存布局

单继承的例子: #include <iostream> using namespace std; class A { public: A() { a = 1; ch = 'a'; //ASCII码97 } private: int a; char ch; }; class C : public A { public: C() { c = 3; } virtual void print() { cout << "C" << endl; } privat

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

构造函数为什么不能为虚函数 &amp;amp; 基类的析构函数为什么要为虚函数

一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数. 2. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到相应的调用.构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀.所以构造函数没有必要是虚

纯虚函数实现接口类:接口编程实战演练

公共的接口要求 //SocketProtocol.h #pragma once class SocketIF { public: //客户端初始化 获取handle 上下文信息 virtual int cltSocketInit() = 0; //客户端发报文 virtual int cltSocketSend(unsigned char *buf, int buflen) = 0; //客户端收报文 virtual int cltSocketRev(unsigned char *buf, in

c++中虚函数和纯虚函数定义

只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非virtual的但与该虚函数具有相同的参数(包括个数和类型)和函数返回值类型的同名函数. 根据什么考虑是否把一个成员函数声明为虚函数? ①  看成员函数所在的类是否会作为基类 ② 看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该

C++虚函数和纯虚函数

只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非virtual的但与该虚函数具有相同的参数(包括个数和类型)和函数返回值类型的同名函数. 根据什么考虑是否把一个成员函数声明为虚函数? ①  看成员函数所在的类是否会作为基类 ② 看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该