C++C++获得private的变量-偷走private

private提供了针对数据的包,使得private成员只能于接近自身之积极分子函数和近似的友元访问,其他的函数或者类想要拜访private成员只能通过此类所提供的set和get的计开展走访,

要返回其指针或引用(effective
C++中涉及了要是避免返回对象中元件的援,指针,或迭代器。这样见面增高封装性,帮助
const 成员函数产生 const
效果,并拿悬空句柄产生的可能降低到低于,所以只是这个措施并无是特别的好)

 

然而如你想获得一个接近的private成员,但是该类的既于品种被大量的用,或者是坐其他的由来,你未曾章程上加get和set方法时,又当怎样取得该类的private成员为?

自我总发生了以下几种植方式

 

方法一:重定义

#define  private public

示例

A.h定义

#pragma once
class A
{
    int j;
public:
    A() :i(10), j(20)
    {

    }
    template<class Type>
    void show(Type t)
    {
        cout << "Hello" << endl;
    }
private:
    int i;
};

main.cpp

#include <iostream>
#define private public
#include "A.h"
using namespace std;


int main()
{
    A a;
    cout << a.i << endl;
    //cout<<a.j<<endl;无法获得
    system("pause");
    return 0;
}

拖欠方式的亮点的是简简单单不过为发生许多之缺陷

1.若在看似的定义时无指定访问标号关键字(public,protected,private),使用默认的private访问限制,那么该措施就是无法直达目的了,比如此处的j就无法获得

2.下跌代码的可读性,改变之一个至关重要字之含义,没有注意到马上一点的程序员会产生困扰

3.拿装有以了private访问的标号的积极分子的造访等级都成了public,降低了数量的封装性

 

 

方法二:模拟内存法

A.h定义

#include <iostream>
#include "A.h"
using namespace std;


int main()
{
    A a;
    void *p = &a;
    cout << "j:" << *(int*)p << endl;
    cout << "i:" << *((int*)p+1)<< endl;// *(int*)((char*)p+4)
    system("pause");
    return 0;
}

C++标准被求,在跟一个访问区域中,成员的排列只待符合于晚出现的成员在类的分子被发出于高的地点即可,成员之内或会见以数量对齐所需,添加一些字节

即诸编译器都是吧一个之上之造访区域连在一起,安装声明的各个成为一个老是的区域

为此类A的一个目标的内存布局类似于这样:

 

指针p指向j,将p加上一个int长度要4独char长度就可指向i了

 

不过以此方式的弱点也要命明确,需要程序员自己对类的内存布局有比较强之询问,考虑到数量对齐,虚函数,不同编译器的落实等等方面

 

按部就班以下简单种状态

1、数据对齐

A.h定义

#pragma once
class A
{
    char j;
public:
    A() :i(10), j(20)
    {

    }
    template<class Type>
    void show(Type t)
    {
        cout << "Hello" << endl;
    }
private:
    int i;

};

char
j占用了一个byte,而i为了数据对齐,在内存布局上连无是跟j紧守的,而是隔了3个byte,

故此博得i和j的间距和达一个同,只是j的档次变了

#include <iostream>
#include "A.h"
using namespace std;


int main()
{
    A a;
    void *p = &a;
    cout << "j:" << *((char*)p) << endl;
    cout << "i:" << *((int*)p+1)<< endl;
    system("pause");
    return 0;
}

 

2.加入虚函数

A.h定义

#pragma once
class A
{
    int j;
public:
    A() :i(10), j(20)
    {

    }
    virtual void show()
    {

    }
    template<class Type>
    void show(Type t)
    {
        cout << "Hello" << endl;
    }
private:
    int i;

};

编译器为了支持虚函数,会当相近的各国一个目标中,产生一个分外的虚函数指针指向相应的虚函数表,不同之编译器对这指针处理不同,有硌用它们位于了类似对象的尾端,有的拿它们放在了接近对象的开始处于

vs2013以她置身了接近的起处

故而类A的一个对象的内存布局应该接近于这样:

内需将p加上4单字节后才能够凭借于j

 

 

#include <iostream>
#include "A.h"
using namespace std;


int main()
{
    A a;
    void *p = &a;
    cout << "j:" << *((int*)p+1) << endl;
    cout << "i:" << *((int*)p+2)<< endl;
    system("pause");
    return 0;
}

故而要是虚函数过多,又投入了虚继承,
类里面还要生出大量程序员自己定义之种类,那么该方法就是会见老辛苦了。

 

 

方式三:李代桃僵

A.h的定义

#pragma once
class A
{
    char j;
public:
    A() :i(10), j('b')
    {

    }
    virtual void show()
    {

    }
    template<class Type>
    void show(Type t)
    {
        cout << "Hello" << endl;
    }
private:
    int i;

};

李代桃僵C++法是拟内存布局之别样一个兑现方式

咱们看看本A里发生一个虚函数,一个j和一个i

倘若直白使用模拟内存法的口舌会大麻烦

 

为此我们可另外声明一个靶B,它的内存布局和A的同,只是i和j的访问限制变成了public

这般我们好将一个指向A的靶子的指针当做一个指向B的靶子指针来行使

#include <iostream>
#include "A.h"
using namespace std;

class B
{
public:
    char j;
public:
    B() :i(10), j('b')
    {

    }
    virtual void show()
    {

    }
    /*template<class Type>
    void show(Type t)
    {
        cout << "Hello" << endl;
    }*/
public:
    int i;

};
int main()
{
    A a;
    B *b = (B*)&a;
    cout<<"j:" << b->j << endl;
    cout<<"i:" << b->i << endl;
    system("pause");
    return 0;
}

非虚成员函数show放在函数段落遭遇,并无在近似对象的布局中据为己有空间,所以发生没有发出show函数都可以

以B的目标的内存布局以及A一样,只是看限制不同,所以可以采用对B对象的条条框框去访问A的对象

一个指向B对象的指针实际对了一个A对象,对B中j和i的造访实际上是对A对象中i和j的看

 

欠方式模拟内存法容易了过多,但您用额外声明一个B对象的概念,而且得要包B对象的内存布局要同A对象的平等

 

 

办法四 特化函数模板法

a.h的定义

#pragma once
class A
{
    char j;
public:
    A() :i(10), j('b')
    {

    }
    virtual void show()
    {

    }
    template<class Type>
    void show(Type t)
    {
        cout << "Hello" << endl;
    }
private:
    int i;

};

 

此间我们发现A有个函数模板show,所以我们可以以对函数模板show进行特化的不二法门合法的取得i和j的public访问权限

#include <iostream>
#include "A.h"
using namespace std;


class B
{

};
template<>
void A::show(B b)
{
    cout << "j:"<<this->j << endl;
    cout << "i:" << this->i << endl;
}
int main()
{
    A a;
    a.show(B());
    system("pause");
    return 0;
}

该方法成立,简单,但也发瑕疵就是是相应的类必须使发成员模板,并且该模板的拜会限制也public才堪

 

 

总结

 

方法 优点 缺点 可移植性
重定义 简单

1.如果在类的定义时不指定访问标号关键字(public,protected,private),使用默认的private访问限制,那么该方法就无法达到目的了,比如这里的j就无法获得

2.降低代码的可读性,改变的一个关键字的意义,会没有注意到这一点的程序员照成困扰

3.将所有使用了private访问的标号的成员的访问等级都变成了public,降低了数据的封装性

模拟内存法 虚函数过多,又加入了虚继承, 类里面又有大量程序员自己定义的类型时,那么该方法就会很麻烦了。需要程序员对内存布局有较深的认识
李代桃僵 简单,可能在有些人看来比较清楚 需要额外声明一个B对象的定义,而且必须要确保B对象的内存布局要与想要访问的A对象的一致
特化函数模板法 合理,简单 相应的类必须要有成员模板,并且该模板的访问限制为public才可以