Учитывая этот надуманный пример:
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
ожидает derived_exception
. Конечно, человек может сказать, что фактическим типом исключения является 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
, то мы вернемся к той же проблеме.