1

我遇到了这个设计问题。这是故事:

我有一个基类,它定义了一些这样的方法:

virtual double & f(double x);

在回答某些查询时,基类将调用其中一个来请求对子类中某些数据的引用。问题是,这些 f 方法在子类中返回一条可选的数据。换句话说,根据子类, f 要求返回的内容可能根本不存在。基类中的逻辑可以保证在子类不存在的时候不会调用这样的f(),所以原则上这个子类不需要实现这个方法,但是我不想做方法纯虚拟,因为无论如何子类都需要可实例化。不方便的是 f 的返回类型需要引用,所以我不能简单地返回一些垃圾值。

所以基本上我正在寻找一种“优雅”的方式来返回一个虚拟引用,如果程序正常工作,无论如何都不会调用它,但理想情况下会通过捕获错误调用来帮助调试。f 的签名对于可读性很重要,所以理想情况下我不想更改它。

我想我可以在类中声明一个虚拟的静态双精度 DATA_NOT_EXIST 变量并返回它,但它看起来有点难看。有更好的想法吗?当你不得不返回“null”引用时,你最喜欢的方式是什么?

提前致谢。


编辑:

我想将这些方法保留在基类中,尽管在子类中声明它们似乎更好,因为基类试图处理一些不适用于所有子类的逻辑(这本身是一个糟糕的设计吗?)。像这样:基类代表鼠标,子类中的可选数据代表左/中/右按钮。任何特定的子类可能没有某些按钮,但无论如何基类仍然处理按钮点击,假设可能有也可能没有按钮。


编辑:这里有一些源代码来说明我的意思。在基类中:

#include <cassert>
struct Base
{
  double & basef(int x)
  {
    assert(x >= 0 && x < 20);
    if (x < 10) return f1(x);
    else return f2(x);
  }
  virtual double & f1(int x);
  virtual double & f2(int x);
};

struct Sub1 : Base
{
  double & f1(int x) { return a[x]; }
  double & f2(int x) { return b[x - 10]; }
  double a[10];
  double b[10];
};

struct Sub2 : Base
{
  double & f1(int x) { return a[x]; }
  double & f2(int x) { /* nothing to return here! */ }
  double a[10];
};
4

2 回答 2

2

您有几个选择,没有一个要求您通过取消引用空指针将未定义的行为引入程序中,正如现在两个答案所建议的那样。

1)抛出异常。消除不可预测性并使其成为您设计的一部分:

// default implementation in base class
virtual double& f2(int x)
{
    throw std::runtime_error("No value defined");
}

2)使用boost::optional<double&>

// default implementation in base class
virtual boost::optional<double&> f2(int x)
{
    return boost::optional<double&>();
}

// call-site
auto value = x->f2(0);
if (value)
    do_something(*value);

3)使用double*(穷人的boost::optional):

// default implementation in base class
virtual double* f2(int x)
{
    return nullptr;
}

// same call-site as before

4)从根本上改变设计以避免这种情况。

所有这些都是更好的解决方案,因为它们可靠且可预测。

于 2012-10-09T15:15:19.007 回答
1
double& Dummy() { return *(double*)nullptr; }

如果您的编译器足够聪明地意识到这是一个 nullptr 访问并发出警告,请尝试使用另一个可能导致崩溃的值,例如 <4096 的任何值(合理地,现代系统应该完全禁止第一个内存页来捕获 nullpointer取消引用),〜0或类似的东西,或者使指针成为全局变量。

当然,我通常会做类似的事情

double& Dummy() { ASSERT(false); }

并且仅在编译器不知道不返回的函数时才返回引用。

于 2012-10-09T09:56:39.903 回答