c++ - 转换到子对象进行测试 - 此代码是否符合标准?

标签 c++ c++11 c++14 language-lawyer memory-model

TL;博士
这个转换/函数调用是合法的、符合标准的 C++11/14 代码吗?
如果不是,是不是没有虚函数(如果 std::is_standard_layout<Module> 变为真)?
(注意:它适用于我迄今为止测试过的每个编译器......)

class Module
{
protected:
    virtual float protectedVirtualFunction(float f) { return f*f*f; }
    float protectedFunction(float f) { return f*f; }
};

class ModuleTester : public Module // consists of ONLY aliases
{
public:
    using Module::protectedFunction;
    using Module::protectedVirtualFunction;
};

int main()
{
    Module module;  //assume this is a pre-existing instance
    // Is this legal?
    ModuleTester* testerMask = static_cast<ModuleTester*>(&module); 
    testerMask->protectedFunction(4.4f);
    testerMask->protectedVirtualFunction(4.4f);
}
附加信息
通常,我的目标是仅在编写 UnitTests 时测试类公共(public) API。
在某些情况下——比如当你处理无法更改的遗留代码时——访问私有(private)成员更实用。
因此,假设我们无法更改设计(DI、解耦...),我看到以下解决方案:
  • 公开私有(private)成员(损害所有封装)
  • 老把戏:#define private public在测试环境中
  • “测试者”模式(在示例代码中使用)

  • 使用这种“测试者”模式的标准方式是这样的,这应该是合法的:
        ModuleTester tester;
        tester.protectedFunction(4.4f);
        tester.protectedVirtualFunction(4.4f);
    
    但是,有时我有一个现有的实例,如果我可以在它上面应用这个“测试器掩码”以获得访问权限,那就太好了。
    我的猜测是,一旦我使用虚拟功能并不再是“标准布局”,严格来说可能会有“未定义的行为”。但是,如果我只在派生类中定义别名,那么只要我对 Module 和 ModuleTester 使用相同的编译器,我就看不出这怎么会出错。
    编辑:我发现了一个类似的方法,它不使用显式指针转换( https://stackoverflow.com/a/1725107/649700 )。它有效,可以说可读性较差,并且可能不会改变“合法性”状态。
    (module.*&ModuleTester::protectedVirtualFunction)(4.4f);
    
    其他一些很好的问题:
    reinterpret_cast from object to first member ,
    How do I unit test a protected method in C++?

    最佳答案

    这将是未定义的行为,因为 &module不指向对象 ModuleTester 的子对象:

    8.5.1.9 Static cast [expr.static.cast]
    11 A prvalue of type “pointer to cv1 B ”, where B is a class type, can be converted to a prvalue of type “pointer to cv2 D ”, where D is a class derived (Clause 13) from B , if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If B is a virtual base class of D or a base class of a virtual base class of D , or if no valid standard conversion from “pointer to D ” to “pointer to B ” exists (7.11), the program is ill-formed. The null pointer value (7.11) is converted to the null pointer value of the destination type. If the prvalue of type “pointer to cv1 B ” points to a B that is actually a subobject of an object of type D , the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.


    #define private public也不是一个好主意:

    2 A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 4, or to the attribute-tokens described in 10.6.

    关于c++ - 转换到子对象进行测试 - 此代码是否符合标准?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61008039/

    相关文章:

    c++ - C++显示指定文本文件的内容

    c++ - C++中对象的定义

    c++ - strlen() 不适用于字符串变量

    c++ - 在奇怪的重复模板类中使用方法的返回类型作为另一个方法的参数类型

    javascript - 从控制台将 MongoDB 字段的类型更改为整数

    c++ - DbgHelp.dll 是 Windows 内置的吗?我可以相信它在那里吗?

    c++ - 如何在线程c++11中调用二类成员函数中的一类成员函数

    c++ - 在程序中使用同一类的两个不同堆栈时出现段错误

    c++ - 准备 C++ Json 请求

    c++ - 使用 Gtkmm 创建信号