前几天笔试adobe,出了这样一个题,当时只想到通过指针的偏移量来访问,但是由于对C++的类对象布局不是很有把握,就随便写了个答案,今天上百度搜了下,发现好几种方法,拿出来一起分享。
先看一个类
#include <stdio.h>
class A
{
private:
char *str;
public:
A(): str("nothing"){};
};
int main()
{
A a;
return 0;
}
如何输出a的私有成员str所指向的字符串"nothing"?可以任意添加代码,但不可以修改这个类。
★★方法一:
在定义A前,加一句“#define private public”。该方法可以欺骗编译器,让它把“private”当作“public”,然后就可以用“a.str”了。
达到了我们的目的,只可惜这个方法有点“左道旁门”。
★★方法二:
a.str的地址就是a的地址,所以用“puts(*(char**)&a);”即可访问a.str。
★方法二变种:
方法二不错,但如果str不是类的第一个成员变量,就会有点麻烦。比如,把A改成如下形式:
class A
{
private:
char d;
char *str;
public:
A(): str("nothing"){};
};
d占一个字节,a.str的地址相对于a的地址,偏移量为1,可以这么用“puts(*(char**)((char*)&a+1));”。这看似不错,但没有考虑字节对齐
问题。为了能高效的访问变量,编译器可能会以空间换时间,采取字节对齐措施。字节对齐后,程序高效了,但对我们而言就麻烦了。str的地
址的偏移量未必是1,可以是2、4、8等,怎么才能获取a.str的偏移量呢?别急,我们可以给该方法打打补丁。
☆方法二变种的补丁:
在定义A前,加一句“#pragma pack(1)”,这行代码可以让编译器按1字节进行对齐,这样以后就可以放心大胆地用“puts(*(char**)(char*)
&a+1));”了。
★★方法三:
方法二的变种打了补丁后,也有了“左道旁门”的“嫌疑”。方法三就显得“高尚”多了。构造一个和A相似的类,但增加了一个非虚成员函数
,用来返回str的地址。
#include <stdio.h>
class A
{
private:
char *str;
public:
A(): str("nothing"){};
};
class B
{
private:
char *str;
public:
B(): str("nothing"){};
char *get()
{
return str;
}
};
int main()
{
A a;
puts(((B*)(&a))->get());
return 0;
}
★★方法四:
和方法三一样,也是构造一个新的类。但有所不同的是,“private”变成了“public”。B的布局和A相同,即同名变量的偏移量相同。这样,
我们就可以把A实例的指针转化为B*类型,来访问str了。
#include <stdio.h>
class A
{
private:
char *str;
public:
A(): str("nothing"){};
};
class B
{
public:
char *str;
public:
B(): str("nothing"){};
};
int main()
{
A a;
//或“puts(((B*)(&a))->str);”
puts(reinterpret_cast<B*>(&a)->str);
return 0;
}
转载自:
http://bbs.byr.cn
分享到:
相关推荐
#include <stdio.h> class A { private: char *str; public: A(): str("nothing"){}; }; int main() { A a; return 0; }
类的对象不能直接访问类声明的私有成员变量,否则破坏了信息隐藏的目的。 在C++中,为了防止某些数据成员或成员函数从外部被直接访问,可以将它们声明为private,这样编译器会阻止任何来自外部非友元的直接访问。 ...
外部访问类的私有成员+修改虚表 这种操作说明了C++的无所不能
原则上,C++类中私有变量不允许在类之外的其他任何地方访问,一般来说功能完善的类都会提供get,set方法来操作类属性值,还有是是通过友元访问。但是!但如果没有get、set方法都没有提供,也没有定义友元,比如使用...
当位于基类的名称之前时,private 关键字指定基类的公共成员和受保护成员为派生类的私有成员。 类中成员的默认访问是私有的。结构或联合中成员的默认访问是公共的。 基类的默认访问对于类是私有的,而对于结构是公共...
在面向对象的编程范式中,封装都是必不可少的一个概念,而在诸如 Java,C++等传统的面向对象的语言中, 私有成员是实现封装的一个重要途径。但在 JavaScript 中,确没有在语法特性上对私有成员提供支持, 这也使得...
②将Girl类作为Boy类的友元类,在Girl类的成员函数VisitBoy(Boy & )中访问Boy类的私有成员,观察程序运行结果。 ③在Boy类的某成员函数VisitGirl(Girl & )中试图访问Girl类的私有成员,观察编译器给出的错误信息,...
1 、定义一个时间类Time,有三个私有成员变量Hour、Minute、Second,定义构造函数、析构函数以及用于改变、获取、输出时间信息的公有函数,主函数中定义时间对象,并通过调用各种成员函数完成时间的设定、改变、获取...
原因很简单大家都知道,静态成员函数不能访问非静态成员,这是因为静态函数属于类而不是属于整个对象,静态函数中的 member可能都没有分配内存。静态成员函数没有隐含的this自变量。所以,它就无法访问自己类的非...
私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们。私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以...
当我们在程序中声明一个对象时,编译器为调用构造函数(如果有的话),而这个调用将通常是外部的,也是说它不属于class对象本身的调用,假如构造函数是私有的,由于在class外部不允许访问私有成员,所以这将导致...
类中的公用成员对外部代码是开放的,通常情况下,程序中的其它代码通过类的 公用成员函数来访问类的私有成员。 2.4 构造函数和析构函数的主要作用是什么?它们各自有什么特性? 【解答】 构造函数是类的一种特殊...
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。 (1) 基类成员对其对象的可见性: 公有成员可见,其他不可见...
关键字private可以将类的成员说明为是私有的,它不能直接被对象访问。 其实,说白了是对于公有成员,我们可以利用对象来进行直接调用,比如说: class Cat { public: int weight; }; int main() { Cat ...
只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是...
(2)C++类中包含私有、公有和保护成员 类的访问控制机制体现在类的成员中可以有公有成员、私有成员和保护成员。对于外界而言,只需要知道对象所表现的外部行为,而不必了解内部实现细节。封装体现了面向对象方法的...
类及对象的访问权限 类中的成员函数可以直接访问类中的数据成员(包括私有成员、公有成员、保护成员); 类中的成员函数可以相互访问; 类的对象只能访问类的公有成员,不能访问私有成员及保护成员
根据软考中的一道题,做的一个小小的例子,看完以后就会对继承关系有个清晰的了解,试题:在C++语言中,已知3个类O、P和Q,类O中定义了一个私有方法F1、一个公有方法F2和一个受保护的方法F3:类P和类Q是类O的派生类 ...