RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1524726
Accepted
ramzan
ramzan
Asked:2023-06-08 22:53:43 +0000 UTC2023-06-08 22:53:43 +0000 UTC 2023-06-08 22:53:43 +0000 UTC

如何访问类的私有成员?

  • 772

面试问题的网站有以下问题:

class Something {
public:
    Something() {
        topSecretValue = 42;
    }
    bool somePublicBool;
    int somePublicInt;
    std::string somePublicString;
private:
    int topSecretValue;
};

有必要[在不触及原始类的情况下]获取 的值topSecretValue。这是解决方案:

class SomethingReplica {
public:
    int getTopSecretValue() { return topSecretValue; }
    bool somePublicBool;
    int somePublicInt;
    std::string somePublicString;
private:
    int topSecretValue;
};

int main(int argc, const char * argv[]) {
    Something a;
    SomethingReplica* b = reinterpret_cast<SomethingReplica*>(&a);
    std::cout << b->getTopSecretValue();
}

我的问题是,这样的解决方案有效吗?我们可以转换为任意类吗?如果没有,这个问题是否有有效的解决方案?

c++
  • 3 3 个回答
  • 113 Views

3 个回答

  • Voted
  1. Best Answer
    user7860670
    2023-06-09T01:14:42Z2023-06-09T01:14:42Z

    0号:德拉图蒂

    实例化模板时不使用访问检查。

    template<typename x_Ptr>
    struct Get
    {
        static inline x_Ptr ptr;
    };
    
    template<auto x_ptr>
    struct Access
    {
        static inline int dummy{(Get<decltype(x_ptr)>::ptr = x_ptr, 0)};
    };
    
    #include <string>
    #include <iostream>
    
    // класс без изменений!
    class Something {
    public:
        Something() {
            topSecretValue = 42;
        }
        bool somePublicBool;
        int somePublicInt;
        std::string somePublicString;
    private:
        int topSecretValue;
    };
    
    template struct Access<&Something::topSecretValue>;
    
    int main()
    {
        Something something{};
        ::std::cout << something.*(Get<int Something::*>::ptr);
    }
    
    

    在线编译器

    • 5
  2. Harry
    2023-06-08T23:24:57Z2023-06-08T23:24:57Z

    在这里,来自Sutter - 当时各种 C++03 方式 :)

    考虑以下头文件。

    // Файл x.h 
    // 
    class X { 
    public:
        X() : private_(1) { /*...*/ }
        template<class T>
        void f( const T& t ) { /*...*/ }
        int Value() { return private_; }
        // ...
    private: 
        int private_; 
    };
    

    显示任意调用代码如何直接访问private_.

    罪魁祸首 #1:伪造者

    伪造者的方法是复制被伪造的类的定义,并进行我们需要的所有更改,例如:

    // Пример 15-1: ложь и подделка
    //
    class X {
        // Вместо включения файла x.h, вручную (и незаконно)
        // дублируем определение X и добавляем строку наподобие
        // этой: 
        friend ::Hijack( X& );
    };
    void Hijack( X& x ) {
        x.private_ = 2;      // Злобный смех
    }
    

    当然,这样做是不合法的。这是非法的,只是因为它违反了单一定义规则,该规则表示如果一个类型(在我们的例子中,X)被定义了不止一次,那么它的所有定义都必须相同。上面示例中使用的对象,虽然它的名称X和外观类似于,但与程序代码的其余部分使用的对象X不同。X然而,这种“hack”适用于大多数编译器,因为对象数据的位置将保持不变。

    罪魁祸首 #2:扒手

    扒手会安静地工作——替换类定义的含义,例如,如下所示。

    // Пример 15-2: использование макромагии
    //
    #define private public        // Не законно!
    #include "x.h"
    void Hijack( X& x ) {
        x.private_ = 2;           // Злобный смех
    }
    

    这个人是个扒手。记住他灵巧的手指!
    当然,扒手的所作所为是不合法的。例 15-2 中的代码不可移植有两个原因。
     用指令重新定义保留字是不合法的#define。
     在这种情况下,与伪造者的情况一样,同样违反了一个定义的规则。但是,如果对象数据的位置保持不变,则此方法将起作用。

    罪魁祸首 #3:欺诈者

    骗子的作案原理是概念代入。

    // Пример 15-3: попытка имитации размещения данных объекта
    //
    class BaitAndSwitch {// В надежде, что размещение данных в
    public:              // этом классе будет тем же, что и в X
        int notSoPrivate;
    };
    void f( X& x ) {
        (reinterpret_cast<BaitAndSwitch&>(x)).notSoPrivate = 2;
    }                                           // Злобный смех
    

    这个人是个骗子。好好记住!他的广告只是为了把你拖进店里,即使在那里他也一定会设法卖给你一个完全不同的东西,这是广告中讨论的,甚至比其他任何地方都贵几倍。

    当然,骗子的所作所为是不合法的。例 15-3 中的代码是非法的有两个原因。
     不能保证对象X在BaitAndSwitch内存中的位置是相同的——尽管在实践中通常是这样。
     结果reinterpret_cast是未定义的,尽管大多数编译器会完全按照诈骗者的要求去做。毕竟,通过说出神奇的词reinterpret_cast,你迫使编译器相信你并对你准备的欺诈行为视而不见。

    Grata Persona #4:律师

    与(其他)罪犯相比,我们中的许多人并非没有理由更害怕衣冠楚楚、面带微笑的律师。
    考虑以下代码。

    // Пример 15-4: проныра-законник
    //
    namespace {
        struct Y {};
    }
    template<>
    void X::f( const Y& ) {
        private_ = 2;               // Злобный смех
    }
    void Test() {
        X x;
        cout << x.Value() << endl;  // Выводит 1
        x.f( Y() );
        cout << x.Value() << endl;  // Выводит 2
    }
    

    这个人是个知道所有漏洞的律师。他不可能被抓到,因为他太过小心翼翼,既违反了法律条文又违反了法律精神。记住并避免这样的不绅士。
    尽管我很想说“当然,律师做的是不合法的”,唉,我不能这样做,因为在最后一个例子中所做的一切都是合法的。为什么?示例 15-4 使用了我有一个成员函数模板的事实X。提供的代码遵循标准,以便后者保证它将按预期工作。

    • 4
  3. HolyBlackCat
    2023-06-09T01:46:44Z2023-06-09T01:46:44Z

    我们在生产中(只是嘘!)做这样的事情。

    这类似于 @user7860670 的回答,但完全在编译时工作(可以在constexpr-expressions 中使用),并且不会产生额外的运行时变量。

    用法:

    #include <iostream>
    
    class A
    {
        int a;
    
      public:
        constexpr A(int a) : a(a) {}
    };
    
    template struct RegisterMember<"my_a", &A::a>;
    
    int main()
    {
        A a(42);
        std::cout << GetMember<"my_a">(a) << '\n';
    }
    

    执行:

    #include <algorithm>
    #include <cstddef>
    #include <functional>
    
    template <std::size_t N>
    struct ConstString
    {
        char value[N]{};
    
        constexpr ConstString() {}
        constexpr ConstString(const char (&source)[N])
        {
            std::copy_n(source, N, value);
        }
    };
    
    namespace // To avoid ODR violations for duplicate keys.
    {
        namespace detail::PrivateAccess
        {
            [[maybe_unused]] constexpr void _adl_GetMember() {} // Dummy ADL target.
    
            template <ConstString Key>
            struct Reader
            {
                #if defined(__GNUC__) && !defined(__clang__)
                #pragma GCC diagnostic push
                #pragma GCC diagnostic ignored "-Wnon-template-friend"
                #endif
                friend constexpr auto _adl_GetMember(Reader<Key>);
                #if defined(__GNUC__) && !defined(__clang__)
                #pragma GCC diagnostic pop
                #endif
            };
    
            template <ConstString Key, auto Value>
            struct Writer
            {
                friend constexpr auto _adl_GetMember(Reader<Key>)
                {
                    return Value;
                }
            };
        }
    
        template <ConstString Key, typename T, typename ...P>
        [[nodiscard]] constexpr decltype(auto) GetMember(T &&target, P &&... params)
        {
            using detail::PrivateAccess::_adl_GetMember;
            return std::invoke(_adl_GetMember(detail::PrivateAccess::Reader<Key>{}), std::forward<T>(target), std::forward<P>(params)...);
        }
    }
    
    template <ConstString Key, auto Value>
    struct RegisterMember : detail::PrivateAccess::Writer<Key, Value> {};
    
    • 3

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5