Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 变形多态对象_C++ - Fatal编程技术网

C++ 变形多态对象

C++ 变形多态对象,c++,C++,考虑以下代码片段: #include <new> #include <iostream> struct IDivideResult { virtual int result() = 0; virtual int remainder() = 0; }; struct DivideResult : IDivideResult { DivideResult(int result, int remainder) : result_(result), r

考虑以下代码片段:

#include <new>
#include <iostream>

struct IDivideResult {
    virtual int result() = 0;
    virtual int remainder() = 0;
};

struct DivideResult : IDivideResult {
    DivideResult(int result, int remainder) : result_(result), remainder_(remainder) {}
    int result() override { return result_; }
    int remainder() override { return remainder_; }

    int result_, remainder_;
};

struct LazyDivideResult : IDivideResult {
    LazyDivideResult(int dividend, int divisor) : dividend_(dividend), divisor_(divisor) {}
    int result() override { return Transmogrify()->result(); }
    int remainder() override { return Transmogrify()->remainder(); }

    DivideResult *Transmogrify() {
        int result = dividend_ / divisor_;
        int remainder = dividend_ % divisor_;
        return new (this) DivideResult(result, remainder);
    }

    int dividend_, divisor_;
};

void Print(IDivideResult *div) {
    int result = div->result();
    int remainder = div->remainder();

    std::cout << result << " " << remainder << "\n";
}

int main() {
    IDivideResult *div = new LazyDivideResult(10, 3);
    Print(div);
}
#包括
#包括
结构IDivideResult{
虚拟int result()=0;
虚拟整数余数()=0;
};
结构DivideResult:IDivideResult{
除法结果(整数结果,整数余数):结果(结果),余数(余数){
int result()重写{返回结果}
int rements()重写{返回余数}
整数结果uu1,余数u2;
};
结构LazyDivideResult:IDivideResult{
LazydividResult(整型被除数,整型除数):被除数,除数{
int result()重写{return Transmogrify()->result();}
int rements()重写{return Transmogrify()->rements();}
DivideResult*Transmogrify(){
int结果=被除数/除数;
整数余数=被除数×除数×除数;
返回新的(此)DivideResult(结果,余数);
}
整型被除数,除数;
};
无效打印(IDivideResult*div){
int result=div->result();
int rements=div->rements();

这是未定义的行为

一旦调用
div->result()
,指针
div
将无效,因为您已经结束了它所指向的对象的生存期。您观察到的症状是它“成功”调用了
余数


理论上,一个实现可以假设您只将
DivideResult
传递给
Print
,因为传递
LazyDivideResult
将是UB。

C++编译器不需要使用vtables来实现多态性。事实证明,几乎所有编译器都会这样做。但如果编译器能够看到优化,则可以消除它们,并且仍然导致正确的行为,这是允许的。这可能会有帮助:您是否有兴趣知道如何在没有UB的情况下做到这一点,或者只想确认这一特定代码确实糟糕和错误?我知道如何在没有这种“替换”的情况下实现这一点的方法技巧。我在这里询问编译器的行为。答案似乎是“行为未定义,请参阅编译器文档/代码”。此外,我在
std::launder
函数的示例中也看到过此类技巧。因此,可能没有那么多“未定义”?您需要在函数外部清洗指针,以获得所希望的保证。从c++17中清洗
std::launder
怎么样?Will
std::launder(div)->rem余数()
定义行为?您还需要将洗钱行为传播回
main
,以便
安全地删除
并且为了进一步避免UB,您最好
静态断言(sizeof(DivideResult)它应该是