【问题标题】:Accessing protected members from outside with this trick, but is this valid?用这个技巧从外部访问受保护的成员,但这有效吗?
【发布时间】:2013-03-05 05:47:58
【问题描述】:

如果我有以下课程:

class Foo
{
protected:
    int i;
public:
    Foo() : i(42) {}
};

当然,我无法从外部访问受保护的成员,但我可以做这个小技巧:首先我创建一个继承 Foo 的新类:

class Foo2 : public Foo
{
public:
    int GetI() { return i; }
};

现在,只要我有 Foo 的实例或指向此类实例的指针,我就可以通过强制转换访问受保护的成员(因为我不使用任何其他成员):

Foo *f = new Foo();
Foo f2;
std::cout << ((Foo2*)f)->GetI() << std::endl;
std::cout << (reinterpret_cast<Foo2&>(f2)).GetI() << std::endl;

我明白为什么会这样,但会不会有任何不良后果?编译器不介意,没有任何运行时检查。

【问题讨论】:

    标签: c++


    【解决方案1】:
    reinterpret_cast<Foo2&>(f2)).GetI()
    

    从技术上讲,这是未定义的行为。所以它可能会起作用,但不是必须的。

    【讨论】:

    • 不知道,但是指针技巧还能用吗?
    • 它没有回答主要问题,((Foo2*)f)-&gt;GetI() 怎么样?
    • @ToniPetrina:因为它不能保证你得到想要的结果。不,你不应该使用它。您应该只编写能够保证结果的代码。
    • @ToniPetrina:对我来说更重要的问题是你为什么需要这个技巧?访问规范不是为了愚弄编译器,它是实现可维护且设计良好的代码的一种手段,人类必须维护而不是编译器。
    • 虽然在一般情况下是正确的,但我认为这个简单的例子遇到了一个特殊的例外。它是一种标准布局类型(因为它缺少虚拟对象,并且派生类不添加新数据,所有数据都具有相同的访问权限等)。所以是的,一般来说你是对的,但是由于标准布局类型的规则,这个简单的例子可能是一个例外。
    【解决方案2】:

    您正在将 Foo 对象转换为 Foo2 对象。

    向下转型是从基类转换为派生自 基类。仅当对象在运行时寻址时,向下转换才是安全的 实际上是在处理派生类对象

    为了保护您的代码,您必须使用dynamic_cast 来检查向下转换是否有效。

    不建议使用reinterpret_cast 进行向下转换。使用static_castdynamic_cast

    阅读大量文章,许多人写道不要像你一样使用向下转换。一个危险的例子是在Foo 中有一个virtual void GetI()

    【讨论】:

    • “不推荐使用reinterpret_cast,因为它依赖于编译器的行为。” 误导到了错误的地步。该标准为reinterpret_cast 的使用提供了某些保证,就像该语言中的任何其他构造一样。如果你超越了这些界限,你就会得到未定义的行为。这不是应该/不应该推荐reinterpret_cast的原因。
    • 我知道动态演员会阻止我这样做。你知道使用上面的技巧可能会遇到什么问题吗?
    猜你喜欢
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 2017-08-01
    • 2016-10-01
    相关资源
    最近更新 更多