假设我有一个静态方法,它比较两个对象的近似匹配并返回一些置信度[0,1]。
class Foo
{
...
static double Compare(const Foo& foo1, const Foo& foo2);
...
};
现在,我需要根据配置中的设置返回包含比较详细信息的其他调试信息。 由于此调试信息不会在生产中使用,但仅在测试/调试目的时,我想知道实现它的适当方法是什么。
我至少看到三个选项:
1:在那里创建一个额外的类CompareResult并存储置信度+可选信息。如果您不需要,请不要填写可选信息。
class CompareResult
{
...
private:
double confidence_;
CompareOptionalInfo compare_optional_info_;
...
};
...
static CompareResult Compare(const Foo& foo1, const Foo& foo2);
它似乎是最干净的,但我不确定是否应该将返回结果与可选信息结合起来。
2:使用输出变量(这样我们就不需要创建一个额外的类,但我们的方法签名会增长一点)
static double Compare(const Foo& foo1, const Foo& foo2, CompareOptionalInfo* out_compare_info = nullptr);
3:使用可选信息检索方法单独比较方法。
static double Compare(const Foo& foo1, const Foo& foo2);
static CompareOptionalInfo GetCompareOptionalInfo();
此选项可能需要在方法调用之间存储此可选信息,并从静态比较方法转换为实例比较方法。 但同样,我不确定它是否合适。
根据您的经验,OOP世界中从方法返回可选信息(主要仅在调试模式下使用)的适当方式是什么?
答案 0 :(得分:1)
选项3 根本不是一个好主意:拥有依赖于静态数据的功能是不切实际的,甚至可能成为调试中的错误来源。这样的设计另外不是线程安全的;可惜的是,仅为了调试目的而创建这样的限制!
问题的例子:
double closest = std::max (Foo::compare (x, y), Foo::compare (y,z));
clog << Foo::GetCompareOptionalInfo(); // undefined which info since order of eval
// of function parameter is not guaranteed
double d = Foo::compare (x, y);
DoSomething(); // what if this one does an unexpected compare ?
clog << Foo::GetCompareOptionalInfo();
选项2 是一个可行的解决方案,但它不是很方便:它会强制您创建信息对象,通过地址等传递它们:
Foo::OptionalCompareInfo o1,o2; // cumbersome
double closest = std::max (Foo::compare (x, y, &o1), Foo::compare (y,z, &o2));
此外,您将创建这些可选信息并在生产中传递额外参数,即使您不再更新其中的信息(除非您进行了大量额外的条件编译)!
选项1 非常好!去吧 !它真正受益于OOP范例,并采用了简洁的设计。使用它很实用,并且不会对您的代码施加约束来使用它。
您只需提供一些(隐式)转换功能即可使用CompareResult
,就好像它是double
一样:
class CompareResult
{
public:
CompareResult(double d=0.0) : confidence_(d) {};
operator double() { return confidence_; }
operator bool() { return confidence_>0.5; }
private:
double confidence_;
CompareOptionalInfo compare_optional_info_;
};
您的生产代码不受调试信息的影响。您可以在调试中随时追溯任何给定比较结果的解释,至少如果您存储它:
示例:
auto result = Foo::compare (x, y)
if (result) ... // uses automatically the conversion
auto closest = std::max (Foo::compare (x, y), Foo::compare (y,z));
// here you not only know the closest match but could explain it !
vector<CompareResult> v;
... // populate the vector with 10 000 comparison results
auto r = std::max_element(v.begin(), v.end());
// you could still explain the compare info for the largest value
// if you're interested in the details of this single value
// how would you do this with option 3 or option 2 ?
好的,对于最后一个工作,你还需要一个比较运算符来为你的额外课程。但是这一行代码更多(参见在线演示);-)
最后,可能会发现您的&#34;可选调试信息&#34;可以证明比预期更有用,例如根据要求向用户提供额外的解释。您需要做的就是删除围绕可选信息计算的条件#ifdef DEBUG
。
答案 1 :(得分:0)
我会使用第二个选项来兼容调试器。
在调试模式下,您可以添加其他静态成员。您应该注意不应该禁止它的链接器。
class Foo
{
private:
#ifndef NDEBUG
CompareOptionalInfo debug_out_compare_info_;
#endif
...
static double Compare(const Foo& foo1, const Foo& foo2,
CompareOptionalInfo* out_compare_info = nullptr);
...
};
#ifndef NDEBUG
CompareOptionalInfo Foo::debug_out_compare_info_;
#endif
在gdb中,在任何断点处,您都可以使用:
call Foo::Compare(foo1, foo2, &Foo::debug_out_compare_info_);
print Foo::debug_out_compare_info_. ...