Я пытаюсь поддерживать функцию копирования в некоторых из моих классов и для этого я создал базовый класс (интерфейс). Но в дополнение к этому классу у меня есть другой класс, который наследуется от него и должен переопределить функцию «копирования» и предоставить новый тип возвращаемого значения. Я копирую класс, используя класс-оболочку для автоматического удаления указателя на вновь выделенный объект, когда он больше не используется. Это шаблонный класс, который не квалифицируется как ковариантный тип. То, что я только что описал, выглядит примерно так:
template <T>
struct BASE {
virtual PTR<BASE> copy() const = 0;
};
template <Y>
struct DERIVED : public BASE<Y> {
virtual PTR<DERIVED> copy() const = 0; // ERROR: PTR<DERIVED> not a covarient type to PTR<BASE>.
};
Зная, что это недопустимо в C ++, мне стало интересно, смогу ли я сделать что-то похожее на это, например:
template <T>
struct DERIVED : public BASE<T> {
virtual PTR<DERIVED> DERIVED::copy() const = 0; // Derived classes should override this function and act as if "PTR<BASE<T>> BASE<T>::copy() const" does not exist.
private: // hide function so that "PTR<DERIVED>" function is called, but when dealing with the base class call the following function.
PTR<BASE<T>> BASE<T>::copy() const {
return PTR<BASE<T>>((BASE<T>*)DERIVED::copy()->GetAndRelease()); // Convert the "PTR<DERIVED>" object to a "PTR<BASE<T>>" object.
}
};
Приведенный выше код не компилируется, потому что вы не можете назвать свой класс при определении его в классе. EX: не может делать «DERIVED :: copy», находясь в классе и определяя функцию, по крайней мере, G ++ выдает мне ошибку, когда я это делаю. Стоит отметить, что упомянутый класс «PTR» работает примерно так:
template <T>
struct PTR {
PTR(T* ptr); // set the pointer to the data;
~PTR(); // destroy the object pointed to by "ptr";
T* get(); // get the pointer to the data;
T* GetAndRelease(); // just to simplify the example, this function returns the pointer and makes it so that the class does not delete the pointer when it is deconstructed.
private:
T* ptr;
}
Вы не можете перегрузить в зависимости от типа возвращаемого значения. Простое решение заключается в не сделать copy()
функционировать virtual
интерфейс, а лучше просто вызвать virtual
интерфейс:
class Base {
Base* do_copy() const = 0;
public:
smart_ptr<Base> copy() const { return smart_ptr<Base>(this->do_copy()); }
};
class Derived {
Derived* do_copy() const { return new Derived(*this); }
public:
smart_ptr<Derived> copy() const { return smart_ptr<Derived>(this->do_copy()); }
};
Фраза о том, что виртуальные функции не являются общедоступными, используется в стандартной библиотеке довольно последовательно (я думаю, что исключение std::exception::what()
). Также удобно обходить проблему переопределения, скрывающего другие перегрузки (см., Например, put()
а также do_put()
Члены std::num_put<...>
).
Других решений пока нет …