将对象转换为派生 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);
}
我正在尝试访问由外部库定义和实现的 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);
}