c++-多态和vptr指针

多态的原理

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int a) {
        this->a = a;
    }

    virtual void func(int a)
    {
        cout << "Parent::func(int)..." << endl;
    }

    virtual void func(int a, int b, int c)
    {
        cout << "Parent::func(int ,int ,int )...." << endl;
    }
private:
    int a;
};

class Child :public Parent
{
public:
    Child(int a, int b) :Parent(a)
    {
        this->b = b;
    }
    virtual void func(int a)
    {
        cout << "Child: func(int)..." << endl;
    }

    void func(int a, int b) {
        cout << "Child :func(int ,int )..." << endl;
    }

    virtual void func(int a, int b, int c)
    {
        cout << "Child ::func(int ,int ,int )..." << endl;
    }
private:
    int b;
};

void myFunc(Parent *pp)
{
    pp->func(10);
}

int main(void)
{
    //Parent *pp = new Parent(10);
    //Parent *cp = new Child(100, 200);

    Parent *pp = new Child(100, 200);

    pp->func(10);//Parent ? Child
                    //如果调用一个普通函数,编译器根本就不会查找虚函数表。
                    //只有你调用的函数,是虚函数的时候,才会去查找虚函数表
    // myFunc(pp);
    pp->func(10, 20, 30);

    return 0;
}

验证vptr指针的存在

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
    virtual void func()
    {
        cout << "Parent::func().." << endl;
    }
    virtual void func(int a)
    {
        cout << "Parent::func().." << endl;
    }
private:
    int a;
};

class Parent2
{
public:
    void func()
    {
        cout << "Parent2::func().." << endl;
    }
private:
    int a;
};
int main(void)
{
    Parent p1;
    Parent2 p2;

    cout << "sizeof(p1) " << sizeof(p1) << endl;//多出来的4个字节就是vptr指针所占用的空间。
    cout << "sizeof(p2) " << sizeof(p2) << endl;

    return 0;
}

vptr指针分布初始化

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int a)
    {
        cout << "Parent(int ..)" << endl;
        this->a = a;

        //print();//是调用父类的print() 还是 子类的print()?
                //通过结果 此时调用的父类的print 并不是子类的print
    }

    virtual void print()
    {
        cout << "Parent::print()...a = "<<a << endl;
    }
private:
    int a;
};

class Child :public Parent
{
public:
    Child(int a, int b) :Parent(a) //在调用父类的构造器的时候,会将vptr指针当做父类来处理。
                                    //此时会临时指向父类的虚函数表

    {
        //将子类对象的空间有编程子类对象处理,vptr指针就从指向父类的表 变成 指向子类的表

        cout << "Child (int ,int )" << endl;
        this->b = b;
        print();//此时vptr指针已经回到了 子类的表, 调用的是子类的print函数。

    }

    virtual void print() {
        cout << "Child ::Print()..b = " << b << endl;
    }
private:
    int b;
};

int main(void)
{
    Parent *pp = new Child(10, 20);
    // pp->print();//发生多态

    delete pp;

    return 0;
}

父类指针和子类指针的步长

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int a)
    {
        this->a = a;
    }
    virtual void print()
    {
        cout << "Parent::print a=  " << a << endl;
    }

    int a;
};

class Child :public Parent
{
public:
    Child(int a) :Parent(a)
    {

    }

    virtual void print()
    {
        cout << "Child::print a=  " << a << endl;
    }

    int b;
};

int main(void)
{

    Child array[] = { Child(0), Child(1), Child(2) };

    Parent *pp = &array[0];
    Child *cp = &array[0];

    pp++;

    pp->print();
    cp->print();

#if 0
    pp++;//pp +sizeof(Parent)
    cp++;//cp +sizeof(Child)

    pp->print();
    cp->print();
#endif
    cout << "-----" << endl;

    int i = 0;
    for (cp= &array[0], i = 0; i < 3; i++, cp++) {
        cp->print();
    }

    return 0;
}

原文地址:https://www.cnblogs.com/ygjzs/p/12079563.html

时间: 2024-10-30 20:33:42

c++-多态和vptr指针的相关文章

深入剖析C++多态、VPTR指针、虚函数表

在讲多态之前,我们先来说说关于多态的一个基石------类型兼容性原则. 一.背景知识 1.类型兼容性原则 类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代.通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员.这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决.类型兼容规则中所指的替代包括以下情况: 子类对象可以当作父类对象使用 子类对象可以直接赋值给父类对象 子类对象可以直接初始化父类对象 父类指针可以直接指向子类对

53)vptr指针的分布初始化

1)一个父类: 2)一个子类: 3)我的main函数内容 4)通过结果证明 那么产生了问题,这个print是一个虚函数,不应该  在  我的main函数中   通过调用pp->print,在print函数里面的那个print应该是 子类的啊,为啥是父类的? 1)首先在我运行这个代码: 1 public: 2 Child(int a,int b):Parent(a) 3 { 先执行  父类的 构造函数   也就是那个vptr存的是父类中虚函数表的地址 然后再执行 1 cout<<"

浅谈为什么只有指针能够完成多态及动态转型的一个误区

c++多态由一个函数地址数组Vtable和一个指向Vtable的指针vptr实现. 具体来说,类拥有自己的vtable,类的vtable在编译时刻完成. 每个对象有自己的vptr指针,该指针初始化时指向对象所实现的类的vtable. 关于向上转型的误区: 通常对于向上转型的理解是这样的,当子类对象向上转型(允许隐式)成父类对象时,实际上只是将子类对象暂时看做父类对象,内部的数据并未改变. 对于没有虚函数的对象,这句话是正确的,但是,当引入虚函数后,这样的理解是有问题的,实际上,向上转型的过程中,

虚函数表指针vptr的测试

类的虚函数调用是通过虚函数表实现的.所谓虚函数表,是编译器自动为一个带有虚函数的类生成的一块内存空间,其中存储着每一个虚函数的入口地址.由于函数的入口地址可以看成一个指针类型,因此这些虚函数的地址间隔为四个字节.而每一个带有虚函数类的实例,编译器都会为其生成一个虚函数指针——vptr,在类的对象初始化完毕后,它将指向虚函数表. 这个vptr指针将位于类对象的首部,即作为第一个成员变量,处于类对象代表的内存块的前四个字节中.为了便于理解和复习,在此将其内存结构以图示之. 查阅资料得知,C++标准并

【C++第十课】---继承和多态

一.函数的重写 什么叫函数的重写呢?在子类中和在父类中定义的函数类型是一样的就叫做函数的重写,注意这里的函数重写和函数重载的区别. 问题的引入:那么如果发生了函数的重写那该怎么办,编译器是如何解析的呢? 要想解决这个问题,那么我们首先得搞清楚到底什么是函数重写,下面举例说明: 1.在子类中定义与父类中原型相同的函数 2.函数重写只发生在父类与子类之间 #include <iostream> using namespace std; class Parent { public: void pri

多态&amp;虚函数

(1).对象类型: a.静态类型:对象声明时的类型,编译的时候确定 b.动态类型:对象的类型是运行时才能确定的 class A {}; class B:public A {}; int main() { B* b; A* a=b;//a的静态类型是A*,动态类型(运行时)类型是B* return 0; } (2).多态 a.静态多态:函数重载.泛性编程 int Add(int a,int b) { return a+b; } float Add(float a,float b) { return

C++ 多态的实现原理与内存模型

多态在C++中是一个重要的概念,通过虚函数机制实现了在程序运行时根据调用对象来判断具体调用哪一个函数. 具体来说就是:父类类别的指针(或者引用)指向其子类的实例,然后通过父类的指针(或者引用)调用实际子类的成员函数.在每个包含有虚函数的类的对象的最前面(是指这个对象对象内存布局的最前面)都有一个称之为虚函数指针(vptr)的东西指向虚函数表(vtbl),这个虚函数表(这里仅讨论最简单的单一继承的情况,若果是多重继承,可能存在多个虚函数表)里面存放了这个类里面所有虚函数的指针,当我们要调用里面的函

C++ 多态的实现机制

关键词:多态 虚函数指针 虚函数表 动态绑定 迟绑定 基类 子类  纯虚函数 抽象类 封装+继承+多态 代码重用 接口重用 隐藏规则(子类中的函数和基类中的函数) 一.为什么需要多态,多态的目的是什么? 二.多态有几种实现方式,多态的实现机制? 三.什么纯虚函数和抽象类,为什么需要定义纯虚函数和抽象类? 1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数.2. 存在虚函数的类都有一个一维的虚函数表叫做虚表.类的对象有一个指向虚表开始的虚指针.虚表是和类对应的,虚表指针是和

c++多态原理

1 当类中声明虚函数时,编译器会在类中生成一个虚函数表 2 虚函数表是一个存储类成员函数指针的数据结构 3 虚函数表是由编译器自动生成与维护的 4 virtual成员函数会被编译器放入虚函数表中 5 当存在虚函数时,每个对象中都有一个指向虚函数表的指针(C++编译器给父类对象.子类对象提前布局vptr指针:当进行howToPrint(Parent *base)函数是,C++编译器不需要区分子类对象或者父类对象,只需要再base指针中,找vptr指针即可.) 6 VPTR一般作为类对象的第一个成员