Допустим, у меня есть два класса. base
и derived_from_base
. base
будет содержать множество функций, которые будут управлять определенными аспектами base
и будут использоваться производными классами. Однако я хотел бы сделать так, чтобы можно было связывать вызовы этих функций.
class data_class {};
class base {
public:
base* add_data(data_class* data) {
m_Data = data;
return this;
}
private:
data_class* m_Data;
};
class derived_from_base : public base {
void custom_function() {}
};
int main() {
data_class* someData = new data_class();
// "myClass" has none of the data after this return
derived_from_base* myClass = derived_from_base().add_data(someData);
derived_from_base* myOtherClass = derived_from_base();
// The data is available in this class now.
myOtherClass.add_data(someData);
}
Я попытался передать указатель производных классов this
на базовый класс, но это дало те же результаты.
В моем реальном коде я передаю указатель на функцию add_data
. Однако, когда я отделяю вызов add_data
, данные доступны в myClass
. Я надеялся, что смогу объединить эти звонки воедино. Я отредактирую свой вопрос, включив в него эти две вещи.
Вы могли бы сэкономить время на вводе текста, назвав свой класс derived
вместо derived_from_base
(поскольку нет никакой двусмысленности с соответствующим названием базового класса base
).
Похоже, у вас две проблемы: 1) приведение указателя, возвращаемого add_data
, к указателю derived_from_base
и 2) наличие висячего указателя на временный объект. О чем из этого вы хотели спросить? Первое является ошибкой времени компиляции, поэтому его необходимо устранить до второго. (Если только вы не изменили свой код на base* myClass = base().add_data(someData);
, который, вероятно, демонстрирует то же самое «не имеет никаких данных после этого возврата» без необходимости в производном классе. Наличие двух таких строк с разными данными еще более вероятно продемонстрирует висячий указатель .)
В будущем, пожалуйста, напишите минимальный воспроизводимый примерs. Вы предоставили код, который не компилируется, а затем рассказали об ошибках времени выполнения в нем.
Иногда подобные вещи достигаются с помощью идиомы CRTP.
В вашем случае это будет выглядеть примерно так:
class Base {
private:
// ...
public:
Base* add_data(data_class* data) {
// implementation ...
}
};
template <typename T>
class BaseCRTP : public Base {
public:
T* add_data(class_data* data) {
return static_cast<T*>(Base::add_data(data));
}
};
class Derived : public BaseCRTP<Derived> {
public:
void custom_function() {}
};
int main() {
Derived derived;
derived.add_data(new class_data())->custom_function();
}
Это не лучший стиль по нескольким пунктам. Во-первых, было бы лучше возвращать ссылку, а не указатель. Так что *this
, а не this
.
В любом случае, вводя шаблон промежуточного базового класса, вы перекладываете повторное использование кода на шаблон и вам придется писать оболочку только один раз.
Функция C++23 «вывод этого» должна упростить этот код, чтобы BaseCRTP
больше не требовался.
@RemyLebeau Да, ты прав. Я бы отредактировал это в ответ, но OP помечен как C++20.
ох, я этого не заметил, спасибо
Почему вы ожидаете, что «эта переменная» будет содержать какие-либо данные? Вы передаете его копию базовому классу, который затем сохраняет другую копию в переменной-члене? Кроме того, что бы вы ни ожидали от myClass, это висячий указатель, поскольку временный объект удаляется. Фактически, судя по всему, компилятор должен даже предупредить вас, потому что вы присваиваете указатель базового класса указателю производного класса, что небезопасно.