当一个对象不是派生类时,滥用interpret_cast将其转换为派生类可以吗

is it ok to abuse reinterpret_cast to convert an object to a derive class when it is not?

本文关键字:派生 转换 cast interpret 一个对象 滥用      更新时间:2023-10-16

以下代码正确编译并工作,使我能够访问类的受保护字段。但是这样做可以吗?感觉很脏,但我从Java中知道什么:

#include <iostream>
class Base {
public:
Base() : _f(42) {
}
int getF() { return _f; }
protected:
int _f;
};
class Der : public Base {
public:
void setF(int f) { _f = f; }
};
int main(int argc, char ** argv) {
Base *b = new Base();
std::cout << b->getF() << std::endl;
Der *d = reinterpret_cast<Der*>(b);
d->setF(37);
std::cout << b->getF()<< std::endl;
}

如果我是对的,但这不好,那么有什么好方法可以公开对象的内部封装数据字段,这些字段通常不需要修改,但在测试中确实需要更改?实例是在其他组件内部创建的,因此更改其类型并非易事。

否,如果您假设一个对象的类型为Der,而它不是,则行为是未定义的。这可能会在运行时失败,而且非常严重。除了通常的情况(特别是请求编译器使无效代码崩溃)之外,如果编译器的优化器假设由于您将其强制转换为Der*,那么它的类型必须是Der,那么这可能会在运行时失败。如果随后调用虚拟函数,编译器可能会认为,由于动态类型已被称为Der,因此可以优化虚拟方法查找。

如果我是对的,但这不好,那么有什么好方法可以公开对象的内部封装数据字段,这些字段通常不需要修改,但在测试中确实需要更改?

friend关键字似乎适用于此。此关键字使类的私有(和受保护)成员在类之外可用。由于Base类应该知道哪个类或函数将对其进行单元测试,因此它可以授予对该类或函数的访问权限。

class Base {
friend class BaseTester;
// ...
protected:
int _f;
};
class BaseTester {
public:
static void test() {
Base *b = new Base();
b->_f = 37;
}
};
int main(int argc, char ** argv) {
BaseTester::test();
}

为了完整性,如果出于某种原因无法修改Base,C++的访问检查中有一些漏洞可能会被滥用。这里有一个:

#include <iostream>
class Base {
// ...
protected:
int _f;
};
class BaseHack : public Base {
public:
static constexpr int Base::*_f = &BaseHack::_f;
};
int main(int argc, char ** argv) {
Base *b = new Base();
b->*BaseHack::_f = 37;
}

BaseHack中,表达式&BaseHack::_f是允许的,因为它命名了通过自己的类访问的基类的受保护成员。但由于_f实际上是在类Base中定义的,所以它的类型是int Base::*而不是int BaseHack::*,并且没有规则阻止它用于访问Base的成员。