C++幕后故事(一)--this指针调整

读者若是以为我文章还不错的,但愿能够多多支持下我,文章能够随便转发,保留原出处就能够了。或者关注个人微信公众号:cpp手艺人。ios

C++下继承了多个父类,子类是如何访问父类的属性?c++

简单的说经过调整子类的this指针以实现访问各个父类的属性。微信

1.什么叫this指针调整?

在c++中多继承过程,根据访问不一样的父类成员变量或者是成员函数,同一个实例对象会出现不一样的基址(对象的地址,相似于你在不一样的场合就会有身份的转换,在家的身份,在学校,在公司的等等),这种现象叫作this指针基址调整。函数

2.如何调整?

1.若是继承的顺序是A,再B,那么初始化时先A再B,内存布局以下图1所示。布局

2.若是继承的顺序仍是是A,再B,那么初始化时的顺序不变,仍是先A再B,可是B存在virtual function,内存布局以下图2所示。

3.若是继承的顺序是A,再B,初始化时仍是先A再B,可是A,B同时存在virtual function,内存布局仍是如图1所示,没有变化。ui

3.思考:

1.那具体又是怎么调整的?this

好比说,继承A,又继承B(先不考虑含有virtual fucntion状况)。为了获取B的成员变量。这是this指针须要偏移字节数为sizeof(A)。从图1上来看,要先越过A所占用的大小。spa

2.为何父类中virtual function,内存布局发生了变化?指针

由于有了virtual function,类中就须要产生指向一个虚函数表的指针。而虚函数表指针是埋在对象的首地址中。因此B有virtual function,那么B的普通成员变量将会偏移到A的前面。code

3.那么既然内存布局发生了变化,可是咱们发现只要继承的顺序不变,那么构造的前后顺序就不会发生变化。说明构造的前后顺序和内存布局没有任何的关系。

4.既然咱们知道了这个this指针的调整,可是有什么用呢?

A.经过指针位置的偏移不就能够访问了原来编译器层面阻止你不想访问的私有属性。
B.这种解决了多个父类下访问父类的属性的解决方案,和多态的方案是很是的类似。
复制代码

若是上面说的你仍是只知其一;不知其二的,我再举个例子说明。

假设在一个家庭中,有你和你爸、你妈。你继承了你爸你妈的全部的财产。

1.假如,你爸在家里占据中主导地位(相似于你爸包含有虚函数)。那么在你的心目中你爸就在第一位的。

2.假如,你妈在家里占据中主导地位(相似于你妈包含有虚函数)。那么在你的心目中你妈就在第一位的。

3.假如,你爸和你妈在家势均力敌(都包含虚函数或者都不包含虚函数)。那么在你的心目中你爸和你妈,你和谁离得近(继承的顺序,谁先继承),谁就在第一位的。

4.可是无论是谁在第一位,你家的户口本上你爸确定是在第一页的(构造函数的顺序不变)。

5.假如,晚上大家一家三口在床上睡觉,你,你爸,你妈这样的顺序。可是假如你想和你妈睡在一块儿。你是否是要翻过你爸这座大山(类的大小),才能和你妈睡在一块儿。(this指针如何调整的)。

6.假如,你想要零花钱,你有两种方式,一种向你妈要,一种是向你爸要。无论是向谁要,是否是都要先找对对象,才能拿到零花钱。在多继承中子类有多个父类,因此访问某个对象的属性(成员变量,函数),则须要先找到基类的地址,为了找到正确的对象都须要进行地址偏移,这就好像你是找你爸仍是找你妈要零花钱都必须先找到这我的。这就是为何须要调整this指针。

4.代码实例:

/**************************************************************************** ** ** Copyright (C) 2019 635672377@qq.com ** All rights reserved. ** ****************************************************************************/

#ifndef objanalyze_h
#define objanalyze_h

#include <iostream>

using std::cout;
using std::endl;

#define VIRTUAL_PARENT_A
#define VIRTUAL_PARENT_B

namespace ObjAnalyze
{
class ParentA {
public:
    ParentA()
    {
        cout << "parent0A address "  << this << endl;
    }

#ifdef VIRTUAL_PARENT_A
    virtual ~ParentA()
    {}
#endif // VIRTUAL_PARENT_A

    void Func0A() {
        cout << "parent0A Func0A, address "  << this << endl;
    }

private:
    int m_age;
    int m_high;

};

class ParentB {
public:
    ParentB()
    {
        cout << "parent0B address "  << this << endl;
    }

#ifdef VIRTUAL_PARENT_B
    virtual ~ParentB()
    {}
#endif // VIRTUAL_PARENT_B

    void Func0B() {
        cout << "parent0B Func0B, address "  << this << endl;
    }

private:
    int m_grade;
    int m_class;

};

class Child : public ParentA, public ParentB
{
public:
    Child()
    {
        cout << "child address "  << this << endl;
    }

    void Func0A() {
        cout << "child Func0A "  << this << endl;
    }

};

void test_this_point_address() {
    cout << "ParentA size " << sizeof(ParentA) << endl;
    cout << "ParentB size " << sizeof(ParentB) << endl;
    cout << "Child size " << sizeof(Child) << endl;

    Child child;
    child.Func0A();
    child.ParentA::Func0A();
    child.Func0B();
    system("pause");}
}

#endif // objanalyze_h
复制代码
1.parentA,B都没有virtual function
// ParentA size 8
// ParentB size 8
// Child size 16
// parent0A address 00AFFD78
// parent0B address 00AFFD80
// child address 00AFFD78
// child Func0A 00AFFD78
// parent0A Func0A, address 00AFFD78
// parent0B Func0B, address 00AFFD80
2.parentA含有virtual function,B没有
// ParentA size 12
// ParentB size 8
// Child size 20
// parent0A address 00EFF7B8
// parent0B address 00EFF7C4
// child address 00EFF7B8
// child Func0A 00EFF7B8
// parent0A Func0A, address 00EFF7B8
// parent0B Func0B, address 00EFF7C4
3.parentB含有virtual function,A没有
// ParentA size 8
// ParentB size 12
// Child size 20
// parent0A address 004FF700
// parent0B address 004FF6F4
// child address 004FF6F4
// child Func0A 004FF6F4
// parent0A Func0A, address 004FF700
// parent0B Func0B, address 004FF6F4
4.parentA,B都含有virtual function
// ParentA size 12
// ParentB size 12
// Child size 24
// parent0A address 0077F870
// parent0B address 0077F87C
// child address 0077F870
// child Func0A 0077F870
// parent0A Func0A, address 0077F870
// parent0B Func0B, address 0077F87C
OptimizationA oe;
OptimizationA of(oe);
OptimizationA og = oe;
OptimizationA oh = OptimizationA(oe); 
// 编译器的角度看,分红两步走
// 1.OptimizationA of (注意此时不会调用OptimizationA的默认构造函数)
// 2.of.OptimizationA::OptimizationA(oe) (调用拷贝构造函数)
// 3.og.OptimizationA::OptimizationA(oe) (调用拷贝构造函数)
// 4.oh.OptimizationA::OptimizationA(oe) (调用拷贝构造函数)
复制代码
相关文章
相关标签/搜索