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

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

本文关键字:访问 父类 成员 受保护 派生 对象 转换      更新时间:2023-10-16

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

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

// 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类是我链接到我的程序的某个外部库的一部分。因此,我想通过添加用于访问val_的公共函数或友元声明来避免修改Node类。此外,我想避免创建node对象的副本或从对象移动,因此我想避免创建派生类来移动/复制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++访问私有/受保护的成员:

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);
}

演示

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

你正在将一个东西强制转换为一个类型,那么这个东西就不属于那个类型。

结果,各种滑稽动作都可能随之而来。

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