我正在尝试编写一个带有子测试的Scaler类,该子测试具有一个Score。
缩放器使用其孩子的分数类的缩放方法来重新缩放其值(例如,缩放比例5 = 5/5的1/1或缩放比例5 = 0/5的0/1)。
但是,每当我以DummyTest类作为子代运行代码时,它都会返回“ -nan(ind)/ 5而不是5/5和我的test case fails
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;
}
答案 0 :(得分:3)
您已经成为所谓的object slicing的受害者;我对代码进行了一些简化以更好地说明(通过智能指针还是原始指针接收指针都没有关系……)
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()
中有一个悬挂的引用。