c++ - 可以滥用 reinterpret_cast 将对象转换为派生类吗?

标签 c++ testing

以下代码编译并正常工作,允许我访问类的 protected 字段。但这是一件好事吗?感觉很脏,但我知道什么来自 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,因此可以优化虚方法查找。

And if I am right and this is not ok, what is a good way expose internal encapsulated data fields of an object which normally don't need to be modified, but do need to be changed in testing?

friend 关键字似乎适合于此。此关键字使类的私有(private)(和 protected )成员在类外可用。由于您的 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();
}

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

#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 是允许的,因为它命名了一个基类的 protected 成员,可以通过它自己的类访问。但是因为_f实际上是在类Base中定义的,所以它的类型是int Base::*而不是int BaseHack::*,并且没有规则阻止它被用来访问 Base 的成员。

关于c++ - 可以滥用 reinterpret_cast 将对象转换为派生类吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42031269/

相关文章:

c++ - Qt Creator 中的代码折叠(#pragma 区域)

C++ wchar_t 数组到指针和函数用法

c++ - 从文件中读取数据后 Bool 结果返回 false

java - 使用 Powermock 模拟类的构造函数时出现 ExceptionInInitializerError。如何解决?

java - 如何在 java 8 中模拟 LocalDateTime.now()

c++ - DirectX 12 资源绑定(bind)

testing - intellij 或 android studio - 创建方法测试用例的快捷方式

c# - 验证列表已排序且项目具有特殊字符时获取 NUnit AssertionException

testing - Maven Transitive dependencies of dependencies in test scope included into a package

c++ - 将二维数组作为参数传递给采用一维数组的函数