【问题标题】:Is there a generic way to "unprotect" static const members?有没有一种通用的方法来“取消保护”静态 const 成员?
【发布时间】:2019-04-01 14:51:48
【问题描述】:

有时我会面临这样一种情况,即我获得了一个具有受保护静态成员的类(无法修改),例如

struct foo {
protected:
    static const int x = 42;
    static const int y = 101;
    static const int z = 404;
    // ... and more ...
};

不幸的是,我需要访问这些成员,而不是在派生类中,而是在其他代码中。我是这样写的:

struct bar : foo {
    static const int x = foo::x;
    static const int y = foo::y;
    static const int z = foo::z;
};

但感觉相当笨拙。从长远来看,应该修改类foo 以提供对这些常量的访问,但只要不是这种情况,我希望有更好的东西。我可以沿着

行写一个宏
int x = SOME_MACRO_VOODOO(foo,x);

不过,我想知道是否有办法避免使用宏。我尝试了很多方法,例如这个

struct f {
    protected:
    static const int x = 42;
};

template <typename T, int T::*P>
struct bar : f {
    int get_value() { return this->*P;}
};

int main() {
    bar<f,&f::x>().get_value();
}

失败是因为&amp;f::x 不是指向成员的指针,而只是int *,当然f::x 是不可访问的:

prog.cc: In function 'int main()':
prog.cc:12:16: error: could not convert template argument '& f::x' from 'const int*' to 'int f::*'
     bar<f,&f::x>().get_value();
                ^
prog.cc:12:5: error: 'const int f::x' is protected within this context
     bar<f,&f::x>().get_value();
     ^~~~~~~~~~~~
prog.cc:3:22: note: declared protected here
     static const int x = 42;

【问题讨论】:

  • 这些数据受到保护而不是公开是有原因的。有一份由开发人员编写的合同,而您正试图破坏它。
  • @MatthieuBrucher 问题是合同已经“损坏”,修复它需要时间和漫长的过程,在此之前我需要一种解决方法来访问应该可以访问的东西,但它不是
  • 看这两篇文章:gotw.ca/gotw/076.htmbloglitb.blogspot.com/2010/07/…,了解如何颠覆访问控制。

标签: c++ protected


【解决方案1】:

听起来您正在寻找using declaration。您可以在类定义的上下文中使用using 将成员从基类导入派生类。如果using 具有与您要导入的成员不同的访问规范,那么您实际上在派生类的上下文中“更改”了该成员的访问规范。

struct foo {
protected:
    static const int x = 42;
    static const int y = 101;
    static const int z = 404;
    // ... and more ...
};


struct bar : foo {
    using foo::x;
    using foo::y;
    using foo::z;
};

int main()
{
    // Should work fine
    int a = bar::x;
}

【讨论】:

  • 嗯,我确定我试过 using 并得到一个错误,抱怨 foo::x 不是一种类型,但这有效,真是个面子问题....
  • 我希望有一些模板魔法来允许编写类似bar&lt;foo,x&gt;::value 的东西来检索foo::x(不必单独using 每个成员),尽管正如另一条评论所指出的那样,有是访问受保护数据不是那么容易的充分理由
  • @user463035818:您可能使用using x = foo::x; /*Invalid, foo::x is not a type*/ 进行测试。
  • @user463035818 对于狡猾的模板魔术,请参阅我在问题评论中链接的帖子。
【解决方案2】:
#define BYPASS_STATIC_PROTECTED( CLASS, FIELD ) \
  []()->decltype(auto){ struct cheater:CLASS { using CLASS::FIELD; }; return cheater::FIELD; }()

auto x= BYPASS_STATIC_PROTECTED( foo, x );

我们也可以在成员字段上这样做:

template<class T>
struct tag_t { using type=T; };

#define BYPASS_MEMPTR_PROTECTED_HELPER( FIELD ) \
  [](auto tag){ using T=typename decltype(tag)::type; struct cheater:T { using T::FIELD; }; return &cheater::FIELD; }

#define BYPASS_MEMPTR_PROTECTED( CLASS, FIELD ) \
  BYPASS_MEMPTR_PROTECTED_HELPER(FIELD)(tag_t<CLASS>{})

#define BYPASS_PROTECTED_ON_MEMBER( FIELD ) \
  [](auto& obj )->decltype(auto) { \
    using T = std::decay_t<decltype(obj)>; \
    return obj.* BYPASS_MEMPTR_PROTECTED_HELPER( FIELD )(tag_t<T>{}); \
  }

和类似的成员函数:

#define BYPASS_PROTECTED_ON_METHOD( MEMBER ) \
  [](auto& obj, auto&&...args )->decltype(auto) { \
    using T = std::decay_t<decltype(obj)>; \
    return (obj.* BYPASS_MEMPTR_PROTECTED_HELPER( MEMBER )(tag_t<T>{}))( decltype(args)(args)... ); \
  }

Live examples.

测试代码:

struct foo {
protected:
    static const int x = 42;
    static const int y = 101;
    static const int z = 404;
    // ... and more ...

    int member = 7;

    int method(int v) const { return -v; }
};

std::cout << BYPASS_STATIC_PROTECTED( foo, x ) << "\n";

std::cout << BYPASS_PROTECTED_ON_MEMBER( member )( f ) << "\n";

std::cout << BYPASS_PROTECTED_ON_METHOD( method )( f, 1 ) << "\n";

【讨论】:

    猜你喜欢
    • 2020-01-17
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 2011-05-15
    相关资源
    最近更新 更多