【问题标题】:How to Access a Private Variable?如何访问私有变量?
【发布时间】:2011-03-02 09:13:53
【问题描述】:

这个问题听起来并不像现在这样公然侮辱。

这是一项家庭作业,至少可以说规格表稀缺且设计不佳。我们有一个函数:

double refuel( int liter, GasStation *gs )
{
    // TODO: Access private variable MaxFuel of gs and decrement.
}

听起来很简单?应该是,但是 GasStation 类没有访问私有变量 MaxFuel 的函数。那么我如何使用 refuel 函数访问它呢?

我不考虑创建一个函数setFuel( int liter ),因为如果我更改他的规范,老师总是会非常积极地抱怨。所以......我想我必须围绕它做一些破解,但我不确定如何在不明确更改 GasStation 中唯一的函数并给它一个参数的情况下解决这个问题,以便我可以在这里调用它。

也许有任何提示?

【问题讨论】:

  • 私有变量被设计为被访问。这是什么作业!
  • 让我直说。简而言之,您的任务是,给定一个您无法更改的具体类,从类定义之外专门访问和修改一个没有访问器的私有成员?
  • 记住孩子:只有朋友可以触摸你的私处。
  • 这个教练需要被龙骨牵引。
  • 好吧,阅读 Herb Sutter 的看法 @gotw.ca/gotw/076.htm;尤其是“语言律师解决方案”:-)

标签: c++ class private


【解决方案1】:

refuel(..) 声明为好友函数。否则,你就不走运了。

【讨论】:

    【解决方案2】:

    现在这听起来像是一个非常糟糕的家庭作业。

    反正我能想到三种访问私有数据的方法:

    1. 通过公共成员函数
    2. 班级的friend
    3. 作弊:

      #define private public 
      #include "the_class.h"
      #undef private
      

    前两个是合法的,但需要你改变类。最后一个是“非侵入式”(无论如何,对于“非侵入式”的某些定义),但绝对是非法的(尽管我还没有看到编译器不起作用)。

    【讨论】:

    • #3 脏了!我以前没见过 :)
    • 当然,总是有类型双关语。当然,这也是“作弊”和未定义的。
    • @Michael 你可以看到它yesterday ;-)
    • +1。 3) 实际上帮助我在不重建库的情况下调试 OpenCV。
    【解决方案3】:

    这很脏,但你可以这样做:

    #define private public
    #include "GasStation.h" // Or whatever the name is
    

    现在编译器认为该标头中的所有内容都是公开的。快乐!

    【讨论】:

    • 是编译器错误还是只是在 MS 标头之一中进行了检查?
    【解决方案4】:

    对于你老师的糟糕作业,我有一个合适的糟糕解决方案。

    #define private public
    #include "GasStation.h"
    #undef private
    

    【讨论】:

    • 请不要鼓励他! LOL 朋友是更好的选择!
    【解决方案5】:

    最好的方法是将公共成员函数添加到GasStation

    refuel 设为好友函数是不太安全的做法。

    如果您知道该类中成员 MaxFuel 的偏移量,则绝对不安全的选项可用。然后你可以改变它如下(不要在生产代码中这样做):

    int* max_fuel = reinterpret_cast<int*>( reinterpret_cast<char*>(gs)+MaxFuel_OFFSET );
    *max_fuel = new_value;
    

    【讨论】:

    • 你不是说*max_fuel = new_value;吗?
    【解决方案6】:

    编译并运行一个测试程序。在调试器中运行它并检查 GasStation 的内存布局。计算以字节为单位的确切距离从 GasStation 开始到您需要设置的 int 的距离是多少(请注意,如果它是第一件事并且没有虚函数,那么该距离保证为 0,因此您可以省略前几个步骤)。

    使用该值将指针递增到对象内您需要设置数据的位置,如 Kirill 所示。但是,只是为了成为一个混蛋-您的老师应得的-不要在这里使用任何符号语言...直接使用距离的值,如下所示:

    *reinterpret_cast<int*>(reinterpret_cast<char*>(gs)+42);
    

    或任何 42 应该到达正确的地方。

    如果您真的想成为一个混蛋,请在您的函数中放置一个假变量。编译并运行程序,然后在堆栈上找到这个假变量和 GasStation 指针数据位置之间的距离。然后这样做:

    *reinterpret_cast<int*>(reinterpret_cast<char*>(*reinterpret_cast<char**>(reinterpret_cast<char*>(&my_var)-666)) + 42) = new_value;
    

    【讨论】:

      【解决方案7】:

      显然GasStation 的意义在于提供GasStation::pump(Car&amp;)。这将为您减少 private: unsigned int MaxFuel

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-13
        • 2015-09-25
        • 2012-05-09
        相关资源
        最近更新 更多