鉴于这个人为的例子:
struct point_2d {
point_2d& x( int n ) {
x_ = n;
return *this;
}
point_2d& y( int n ) {
y_ = n;
return *this;
}
int x_, y_;
};
struct point_3d : point_2d {
point_3d& z( int n ) {
z_ = n;
return *this;
}
int z_;
};
int main() {
point_3d p;
p.x(0).y(0).z(0); // error: "point_2d" has no member named "z"
return 0;
}
这个想法是使用“成员函数链接”来能够连续调用多个成员函数。(有很多这样的例子;上面是我能想到的最短的例子。我的实际问题是类似的,如下所述。)
问题是,如果派生类添加了它自己的链接成员函数,但您首先调用基类的成员函数,您会得到一个基类引用,这当然不能用于调用派生类的成员函数。
有没有什么聪明的方法可以解决这个问题并且仍然保持成员函数链接的能力?
实际问题
我的实际问题是我的基类是一个异常,而我的派生类是从基异常派生的类。对于这些类,我也想使用成员函数链接:
class base_exception : public std::exception {
// ...
base_exception& set_something( int some_param ) {
// ...
return *this;
}
};
class derived_exception : public base_exception {
// ...
};
int main() {
try {
// ...
if ( disaster )
throw derived_exception( required_arg1, required_arg2 )
.set_something( optional_param );
}
catch ( derived_exception const &e ) {
// terminate called after throwing an instance of 'base_exception'
}
}
问题是set_something()
返回base_exception
但catch
期望 a derived_exception
。当然,人类可以判断异常的实际类型是 a derived_exception
,但编译器显然无法判断。
这就是我真正要解决的问题,即,如何让基异常类能够在异常对象上设置可选参数,同时返回派生类型的实例。我上面给出的point_2d
例子是(我相信)同一个问题的一个更小更简单的版本,供人们理解,并且解决更小的问题也将解决我的实际问题。
请注意,我确实考虑过制作base_exception
模板并传入派生类型,例如:
template<class Derived>
class base_exception {
// ...
Derived& set_something( int some_param ) {
// ...
return *this;
}
};
我相信实际上确实解决了问题,但它不是一个完美的解决方案,因为如果另一个类more_derived_exception
派生自derived_exception
,那么我们又回到了同样的问题。