将对象转换为派生 class 以访问父 class 的受保护成员

Casting an object to a derived class to access protected members of parent class

我正在尝试访问由外部库定义和实现的 class 的受保护成员。如果可能的话,我想在不复制或移动实例的情况下实现这一目标。

这是一个简化的例子。假设这是来自外部库的代码:

// some_external_library.h

class Node {
    public:
        static Node Create();
    protected:
        Node(int val) : val_(val) {}
        int val_;
};

这就是我想要做的:

// my_code.cpp

#include "some_external_library.h"

Node node = Node::Create();
int val = node.val_; // <-- This is invalid since val_ is protected.

Node class 是我 link 我的程序的一些外部库的一部分。因此,我想通过添加 public 函数或用于访问 val_ 的友元声明来避免修改 Node class。另外,我想避免创建 node 对象的副本或从它移动,所以我想避免创建派生的 class moving/copying Node 实例只是为了访问成员字段。可能吗?

我想出了一个可能的解决方案,它对最小的例子很有效:

// my_code.cpp

#include "some_external_library.h"
class NodeAccessor : public Node {
    public:
        int val() const { return val_; }
};

Node node = Node::Create();
int val = static_cast<const NodeAccessor&>(node).val();

但是,我不确定这是否有效,因为 node 不是 NodeAccessor 的实例。这个标准合规吗?它会导致任何问题吗(例如,在编译外部库期间优化掉 val_)?

是的,这会而且应该会引起问题。

你正在将一个东西转换成一个类型,然后这个东西就不是那个类型了。

结果可能会发生各种滑稽动作。

根本没有办法做您想做的事,这是一件好事!访问保护是有原因的。与他们合作,而不是反对他们。

你做的就是UB

在 C++ 中有一种访问 private/protected 成员的神奇方法:

ISO C++ 标准指定在显式模板实例化的情况下不进行访问检查,以下代码滥用该标准:

template <typename Tag>
struct result
{
  using type = typename Tag::type;
  static type ptr;
};

template <typename Tag> typename result<Tag>::type result<Tag>::ptr;

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
  /* fill it ... */
  struct filler {
    filler() { result<Tag>::ptr = p; }
  };
  static filler filler_obj;
};

template <typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;

然后

struct NodeVal { using type = int Node::*; };
template class rob<NodeVal, &Node::val_>;

最后:

int main() {
  Node node = /**/;
  (node.*result<NodeVal>::ptr);
}

Demo