为什么这段代码返回 -nan(ind)?C++



我正在尝试编写一个Scaler类,该类接受具有分数的子测试。

Scaler 使用其子分数类的量表方法来重新缩放其值(例如,1/1 的量表 5 = 5/5 或 0/1 的量表 5 = 0/5(。

但是,每当我作为孩子使用 DummyTest 类运行我的代码时,它都会返回"-nan(ind(/5 而不是 5/5,并且我的测试用例失败

TEST_CASE("Scaling test returning 1/1 to 5/5")
{
auto test = std::make_shared<DummyTest>(Score(1, 1)); // Tests that always returns 1/1
Scaler scaler(test, 5);
CHECK(scaler.run() == Score(5, 5));
}

这是我的代码:

class Score {
public:
double value;
double maximum;
Score() : value(0), maximum(0) { }                          
Score(double maximum) : value(0), maximum(maximum) { }      
Score(double value, double maximum) : value(value), maximum(maximum) { }
Score scale(double scale) const;
bool success();
};
Score Score::scale(double scale) const {
double a = (value / maximum) * scale;
double b = scale;
return Score(a , b);
}
class Test {
public:
virtual Score run() const;
};
class DummyTest : public Test {
Score score;
public:
DummyTest(const Score& score) : score(score) { }
Score run() const override {
return score;
}
};
class Scaler : public Test {
public:
Test child;
double maximum;
Scaler(std::shared_ptr<Test> child, double maximum) : child(*child), maximum(maximum) { }
Score run() const override;
};
Score Scaler::run() const {
Score c = child.run().scale(maximum);
return c;
}

你已经成为所谓的对象切片的受害者;为了更好地说明,我稍微简化了代码(无论您是通过智能指针还是原始指针接收指针都没有关系......

class Scaler
{
Test child;
Scaler(Test* child, double maximum) : child(*child) { }
//   here!!!
};

确切的情况是将派生类分配给基类的实例。基类(作为值(不能保存派生类的实例,因此属于派生类的所有数据都被"切断",或者换句话说,只有派生类的基类部分被复制到测试成员中。由于它现在是一个真正的Test实例,它将调用Test::run(),它只返回Score(),你最终被 0 除法...

所以现在,正如您已经引入的智能指针一样,然后从中获利:

class Scaler
{
std::shared_ptr<Test> child;
Scaler(std::shared_ptr<Test> const& child, double maximum)
// you don't need the reference counting stuff for the parameter,
// so you can pass as reference
: child(child) // assigning the reference to our member
// (now with reference count management)
{ }
};

更简单的变体是使用原始引用:

class Scaler
{
Test& child;
//  ^ (!)
Scaler(Test& child, double maximum)
: child(child), maximum(maximum)
{ }
};

这甚至允许在测试函数中使用更简单的代码:

DummyTest test(Score 1,1));
Scaler s(test, 5);

但请注意,对于原始引用,您需要确保引用的测试至少与引用测试一样长(或者至少只要引用测试仍在使用其引用(,否则您将遭受未定义的行为。这是由上面的代码片段保证的,但是,如果您这样做,则不会:

Scaler s(DummyTest(Score 1,1));
s.run();

现在,从构造器返回后,DummyTest实例再次被取消,并且您在s.run()中有一个悬而未决的引用。

最新更新